<!DOCTYPE html><html><head><title>Coverage</title><script>

headings = [];

onload = function(){
  headings = document.querySelectorAll('h2');
};

onscroll = function(e){
  var heading = find(window.scrollY);
  if (!heading) return;
  var links = document.querySelectorAll('#menu a')
    , link;

  for (var i = 0, len = links.length; i < len; ++i) {
    link = links[i];
    link.className = link.getAttribute('href') == '#' + heading.id
      ? 'active'
      : '';
  }
};

function find(y) {
  var i = headings.length
    , heading;

  while (i--) {
    heading = headings[i];
    if (y > heading.offsetTop) {
      return heading;
    }
  }
}
</script><style>

body {
  font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: 0;
  color: #2C2C2C;
  border-top: 2px solid #ddd;
}

#coverage {
  padding: 60px;
}

h1 a {
  color: inherit;
  font-weight: inherit;
}

h1 a:hover {
  text-decoration: none;
}

.onload h1 {
  opacity: 1;
}

h2 {
  width: 80%;
  margin-top: 80px;
  margin-bottom: 0;
  font-weight: 100;
  letter-spacing: 1px;
  border-bottom: 1px solid #eee;
}

a {
  color: #8A6343;
  font-weight: bold;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

ul {
  margin-top: 20px;
  padding: 0 15px;
  width: 100%;
}

ul li {
  float: left;
  width: 40%;
  margin-top: 5px;
  margin-right: 60px;
  list-style: none;
  border-bottom: 1px solid #eee;
  padding: 5px 0;
  font-size: 12px;
}

ul::after {
  content: '.';
  height: 0;
  display: block;
  visibility: hidden;
  clear: both;
}

code {
  font: 12px monaco, monospace;
}

pre {
  margin: 30px;
  padding: 30px;
  border: 1px solid #eee;
  border-bottom-color: #ddd;
  -webkit-border-radius: 2px;
  -moz-border-radius: 2px;
  -webkit-box-shadow: inset 0 0 10px #eee;
  -moz-box-shadow: inset 0 0 10px #eee;
  overflow-x: auto;
}

img {
  margin: 30px;
  padding: 1px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
  -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
  max-width: 100%;
}

footer {
  background: #eee;
  width: 100%;
  padding: 50px 0;
  text-align: right;
  border-top: 1px solid #ddd;
}

footer span {
  display: block;
  margin-right: 30px;
  color: #888;
  font-size: 12px;
}

#menu {
  position: fixed;
  font-size: 12px;
  overflow-y: auto;
  top: 0;
  right: 0;
  margin: 0;
  height: 100%;
  padding: 15px 0;
  text-align: right;
  border-left: 1px solid #eee;
  -moz-box-shadow: 0 0 2px #888
     , inset 5px 0 20px rgba(0,0,0,.5)
     , inset 5px 0 3px rgba(0,0,0,.3);
  -webkit-box-shadow: 0 0 2px #888
     , inset 5px 0 20px rgba(0,0,0,.5)
     , inset 5px 0 3px rgba(0,0,0,.3);
  -webkit-font-smoothing: antialiased;
  background: url("");
}

#logo {
  position: fixed;
  bottom: 10px;
  right: 10px;
  background: rgba(255,255,255,.1);
  font-size: 11px;
  display: block;
  width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  -webkit-border-radius: 20px;
  -moz-border-radius: 20px;
  -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
  -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
  color: inherit;
}

#menu li a {
  display: block;
  color: white;
  padding: 0 35px 0 25px;
  -webkit-transition: background 300ms;
  -moz-transition: background 300ms;
}

#menu li {
  position: relative;
  list-style: none;
}

#menu a:hover,
#menu a.active {
  text-decoration: none;
  background: rgba(255,255,255,.1);
}

#menu li:hover .cov {
  opacity: 1;
}

#menu li .dirname {
  opacity: .60;
  padding-right: 2px;
}

#menu li .basename {
  opacity: 1;
}

#menu .cov {
  background: rgba(0,0,0,.4);
  position: absolute;
  top: 0;
  right: 8px;
  font-size: 9px;
  opacity: .6;
  text-align: left;
  width: 17px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  padding: 2px 3px;
  text-align: center;
}

#stats:nth-child(2n) {
  display: inline-block;
  margin-top: 15px;
  border: 1px solid #eee;
  padding: 10px;
  -webkit-box-shadow: inset 0 0 2px #eee;
  -moz-box-shadow: inset 0 0 2px #eee;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}

#stats div {
  float: left;
  padding: 0 5px;
}

#stats::after {
  display: block;
  content: '';
  clear: both;
}

#stats .sloc::after {
  content: ' SLOC';
  color: #b6b6b6;
}

#stats .percentage::after {
  content: ' coverage';
  color: #b6b6b6;
}

#stats .hits,
#stats .misses {
  display: none;
}

.high {
  color: #00d4b4;
}
.medium {
  color: #e87d0d;
}
.low {
  color: #d4081a;
}
.terrible {
  color: #d4081a;
  font-weight: bold;
}

table {
  width: 80%;
  margin-top: 10px;
  border-collapse: collapse;
  border: 1px solid #cbcbcb;
  color: #363636;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
}

table thead {
  display: none;
}

table td.line,
table td.hits {
  width: 20px;
  background: #eaeaea;
  text-align: center;
  font-size: 11px;
  padding: 0 10px;
  color: #949494;
}

table td.hits {
  width: 10px;
  padding: 2px 5px;
  color: rgba(0,0,0,.2);
  background: #f0f0f0;
}

tr.miss td.line,
tr.miss td.hits {
  background: #e6c3c7;
}

tr.miss td {
  background: #f8d5d8;
}

td.source {
  padding-left: 15px;
  line-height: 15px;
  white-space: pre;
  font: 12px monaco, monospace;
}

code .comment { color: #ddd }
code .init { color: #2F6FAD }
code .string { color: #5890AD }
code .keyword { color: #8A6343 }
code .number { color: #2F6FAD }
</style></head><body><div id="coverage"><h1 id="overview">Coverage</h1><div id="menu"><li><a href="#overview">overview</a></li><li><span class="cov high">81</span><a href="#calipso.js"><span class="basename">calipso.js</span></a></li><li><span class="cov medium">70</span><a href="#core/Blocks.js"><span class="dirname">core/</span><span class="basename">Blocks.js</span></a></li><li><span class="cov high">100</span><a href="#core/Cache.js"><span class="dirname">core/</span><span class="basename">Cache.js</span></a></li><li><span class="cov low">30</span><a href="#core/cacheAdapters/memory.js"><span class="dirname">core/cacheAdapters/</span><span class="basename">memory.js</span></a></li><li><span class="cov high">75</span><a href="#core/cacheAdapters/store.js"><span class="dirname">core/cacheAdapters/</span><span class="basename">store.js</span></a></li><li><span class="cov high">96</span><a href="#core/Config.js"><span class="dirname">core/</span><span class="basename">Config.js</span></a></li><li><span class="cov terrible">13</span><a href="#core/Date.js"><span class="dirname">core/</span><span class="basename">Date.js</span></a></li><li><span class="cov high">95</span><a href="#core/Event.js"><span class="dirname">core/</span><span class="basename">Event.js</span></a></li><li><span class="cov terrible">13</span><a href="#core/Form.js"><span class="dirname">core/</span><span class="basename">Form.js</span></a></li><li><span class="cov medium">65</span><a href="#core/Helpers.js"><span class="dirname">core/</span><span class="basename">Helpers.js</span></a></li><li><span class="cov high">100</span><a href="#core/Lib.js"><span class="dirname">core/</span><span class="basename">Lib.js</span></a></li><li><span class="cov medium">50</span><a href="#core/Link.js"><span class="dirname">core/</span><span class="basename">Link.js</span></a></li><li><span class="cov high">84</span><a href="#core/Logging.js"><span class="dirname">core/</span><span class="basename">Logging.js</span></a></li><li><span class="cov high">98</span><a href="#core/Menu.js"><span class="dirname">core/</span><span class="basename">Menu.js</span></a></li><li><span class="cov high">86</span><a href="#core/Module.js"><span class="dirname">core/</span><span class="basename">Module.js</span></a></li><li><span class="cov medium">55</span><a href="#core/Permission.js"><span class="dirname">core/</span><span class="basename">Permission.js</span></a></li><li><span class="cov high">76</span><a href="#core/Router.js"><span class="dirname">core/</span><span class="basename">Router.js</span></a></li><li><span class="cov high">100</span><a href="#core/Storage.js"><span class="dirname">core/</span><span class="basename">Storage.js</span></a></li><li><span class="cov medium">70</span><a href="#core/Table.js"><span class="dirname">core/</span><span class="basename">Table.js</span></a></li><li><span class="cov medium">66</span><a href="#core/Themes.js"><span class="dirname">core/</span><span class="basename">Themes.js</span></a></li><li><span class="cov low">41</span><a href="#core/Utils.js"><span class="dirname">core/</span><span class="basename">Utils.js</span></a></li><li><span class="cov high">100</span><a href="#client/Client.js"><span class="dirname">client/</span><span class="basename">Client.js</span></a></li><a id="logo" href="http://visionmedia.github.com/mocha/">m</a></div><div id="stats" class="medium"><div class="percentage">63%</div><div class="sloc">1878</div><div class="hits">1192</div><div class="misses">686</div></div><div id="files"><div class="file"><h2 id="calipso.js">calipso.js</h2><div id="stats" class="high"><div class="percentage">81%</div><div class="sloc">91</div><div class="hits">74</div><div class="misses">17</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * This is the core Calipso middleware that controls the bootstrapping, and core routing functions, required for</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * Calipso to function.  This is loaded into an Express application via:</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> *     app.use(calipso.calipsoRouter(next);</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> * Further detail is contained in comments for each function and object.</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> * Module exports</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> *     lib : Libraries that can be re-used in each module (avoids repetition), imported lib or utils (not core lib)</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> *     sessionCache : Holds cache of logged in users.</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> *     dynamicHelpers : Helper functions that can be used in views (e.g. getBlock etc.)</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> *     getDynamicHelpers : Function that loads Dynamic helpers (TODO : refactor into single function)</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> *     mr : Tracks running map reduce operations, to ensure that multiple updates do not conflict.</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> *     theme : Link to the currently loaded theme (one per site).</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> *     data : In memory store of common data (e.g. allows caching vs repetitive returns to mongo)</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> *     modules : Object that holds all loaded modules, modules are properties based on their name.</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> *     date : shortcut to Calipso date library (link below)</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> *     form : shortcut to Calipso form library (link below)</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">32</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  fs = require('fs'),</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">  events = require('events');</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">// Core object</td></tr><tr class="hit"><td class="line">38</td><td class="hits">1</td><td class="source">var calipso = module.exports = {</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">  // Router and initialisation</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">  routingFn: routingFn,</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">  init: init,</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">  // Configuration exposed</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">  reloadConfig: reloadConfig,</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  // Core objects - themes, data, modules</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">  theme: {},</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">  data: {},</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">  modules: {}</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">// Load libraries in the core folder</td></tr><tr class="hit"><td class="line">55</td><td class="hits">1</td><td class="source">loadCore(calipso);</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">57</td><td class="hits">1</td><td class="source">function loadCore(calipso) {</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">  fs.readdirSync(__dirname + '/core').forEach(function(library) {</td></tr><tr class="hit"><td class="line">60</td><td class="hits">19</td><td class="source">    var isLibrary = library.split(&quot;.&quot;).length &gt; 0 &amp;&amp; library.split(&quot;.&quot;)[1] === 'js',</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">      libName = library.split(&quot;.&quot;)[0].toLowerCase();</td></tr><tr class="hit"><td class="line">62</td><td class="hits">37</td><td class="source">    if (isLibrary) calipso[libName] = require(__dirname + '/core/' + library);</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">}</td></tr><tr class="hit"><td class="line">66</td><td class="hits">1</td><td class="source">module.exports.loaded = true;</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">/** </td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> * Calipso initialisation</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">72</td><td class="hits">1</td><td class="source">function init(app, initCallback) {</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">74</td><td class="hits">1</td><td class="source">  calipso.app = app;</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">  // Load the calipso package.json into app.about</td></tr><tr class="hit"><td class="line">77</td><td class="hits">1</td><td class="source">  calipso.module.loadAbout(app, rootpath, 'package.json');</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">79</td><td class="hits">1</td><td class="source">  calipso.config = app.config;</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">  // Store the callback function for later</td></tr><tr class="hit"><td class="line">82</td><td class="hits">1</td><td class="source">  calipso.initCallback = function() {</td></tr><tr class="hit"><td class="line">83</td><td class="hits">1</td><td class="source">    initCallback();</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">  // Configure the cache</td></tr><tr class="hit"><td class="line">87</td><td class="hits">1</td><td class="source">  calipso.cacheService = calipso.cache.Cache({</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">    ttl: calipso.config.get('performance:cache:ttl')</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">  // Create our calipso event emitter</td></tr><tr class="hit"><td class="line">92</td><td class="hits">1</td><td class="source">  calipso.e = new calipso.event.CalipsoEventEmitter({maxListeners: calipso.config.get('server:events:maxListeners')});</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">  // Load configuration</td></tr><tr class="hit"><td class="line">95</td><td class="hits">1</td><td class="source">  initialiseCalipso();</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> * Core router function.</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> * Returns a connect middleware function that manages the roucting</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> * of requests to modules.</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source"> * Expects Calipso to be initialised.</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">108</td><td class="hits">1</td><td class="source">function routingFn() {</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">  // Return the function that manages the routing</td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">  // Ok being non-synchro</td></tr><tr class="hit"><td class="line">112</td><td class="hits">4</td><td class="source">  return function(req, res, next) {</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">    // Default menus and blocks for each request</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source">    // More of these can be added in modules, these are jsut the defaults</td></tr><tr class="hit"><td class="line">116</td><td class="hits">4</td><td class="source">    res.menu = {</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">      admin: new calipso.menu('admin', 'weight', 'root', {</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source">        cls: 'admin'</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">      }),</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">      adminToolbar: new calipso.menu('adminToolbar', 'weight', 'root', {</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">        cls: 'admin-toolbar toolbar'</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">      }),</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">      // TODO - Configurable!</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">      userToolbar: new calipso.menu('userToolbar', 'weight', 'root', {</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">        cls: 'user-toolbar toolbar'</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source">      }),</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">      primary: new calipso.menu('primary', 'name', 'root', {</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">        cls: 'primary'</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">      }),</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">      secondary: new calipso.menu('secondary', 'name', 'root', {</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">        cls: 'secondary'</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">      })</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">    // Initialise our clientJS library linked to this request</td></tr><tr class="hit"><td class="line">137</td><td class="hits">4</td><td class="source">    var Client = require('./client/Client');</td></tr><tr class="hit"><td class="line">138</td><td class="hits">4</td><td class="source">    res.client = new Client();</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">    // Initialise helpers - first pass</td></tr><tr class="hit"><td class="line">141</td><td class="hits">4</td><td class="source">    calipso.helpers.getDynamicHelpers(req, res, calipso);</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">    // Route the modules</td></tr><tr class="hit"><td class="line">144</td><td class="hits">4</td><td class="source">    calipso.module.eventRouteModules(req, res, next);</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> * Load the application configuration</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source"> * Configure the logging</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source"> * Configure the theme</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source"> * Load the modules</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> * Initialise the modules</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source"> * @argument config</td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">161</td><td class="hits">1</td><td class="source">function initialiseCalipso(reloadConfig) {</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">  // Check if we need to reload the config from disk (e.g. from cluster mode)</td></tr><tr class="hit"><td class="line">164</td><td class="hits">2</td><td class="source">  if (reloadConfig) {</td></tr><tr class="hit"><td class="line">165</td><td class="hits">1</td><td class="source">    calipso.config.load();</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">  // Clear Event listeners</td></tr><tr class="hit"><td class="line">169</td><td class="hits">2</td><td class="source">  calipso.e.init();</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">  // Configure the logging</td></tr><tr class="hit"><td class="line">172</td><td class="hits">2</td><td class="source">  calipso.logging.configureLogging();</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source">  // Check / Connect Mongo</td></tr><tr class="hit"><td class="line">175</td><td class="hits">2</td><td class="source">  calipso.storage.mongoConnect(calipso.config.get('database:uri'), false, function(err, connected) {</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">177</td><td class="hits">2</td><td class="source">    if (err) {</td></tr><tr class="miss"><td class="line">178</td><td class="hits">0</td><td class="source">      console.log(&quot;There was an error connecting to the database: &quot; + err.message);</td></tr><tr class="miss"><td class="line">179</td><td class="hits">0</td><td class="source">      process.exit();</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">    // Load all the themes</td></tr><tr class="hit"><td class="line">183</td><td class="hits">2</td><td class="source">    loadThemes(function() {</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source">      // Initialise the modules and  theming engine</td></tr><tr class="hit"><td class="line">186</td><td class="hits">2</td><td class="source">      configureTheme(function() {</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">        // Load all the modules</td></tr><tr class="hit"><td class="line">189</td><td class="hits">2</td><td class="source">        calipso.module.loadModules(function() {</td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source">          // Initialise, callback via calipso.initCallback</td></tr><tr class="hit"><td class="line">192</td><td class="hits">2</td><td class="source">          calipso.module.initModules();</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source"> * Called both via a hook.io event as</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> * well as via the server that initiated it.</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">209</td><td class="hits">1</td><td class="source">function reloadConfig(event, data, next) {</td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">  // Create a callback</td></tr><tr class="hit"><td class="line">212</td><td class="hits">1</td><td class="source">  calipso.initCallback = function(err) {</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source">    // If called via event emitter rather than hook</td></tr><tr class="hit"><td class="line">214</td><td class="hits">2</td><td class="source">    if (typeof next === &quot;function&quot;) next(err);</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">  };</td></tr><tr class="hit"><td class="line">216</td><td class="hits">1</td><td class="source">  return initialiseCalipso(true);</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> * Load the available themes into the calipso.themes object</td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">224</td><td class="hits">1</td><td class="source">function loadThemes(next) {</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">226</td><td class="hits">2</td><td class="source">  var themeBasePath = calipso.config.get('server:themePath'),</td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source">    themePath, legacyTheme, themes;</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">  // Load the available themes</td></tr><tr class="hit"><td class="line">230</td><td class="hits">2</td><td class="source">  calipso.availableThemes = calipso.availableThemes || {};</td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">232</td><td class="hits">2</td><td class="source">  calipso.lib.fs.readdirSync(calipso.lib.path.join(rootpath, themeBasePath)).forEach(function(folder) {</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">234</td><td class="hits">2</td><td class="source">    if (folder != &quot;README&quot; &amp;&amp; folder != '.DS_Store') {</td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">236</td><td class="hits">2</td><td class="source">      themes = calipso.lib.fs.readdirSync(calipso.lib.path.join(rootpath, themeBasePath, folder));</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source">      // First scan for legacy themes</td></tr><tr class="hit"><td class="line">239</td><td class="hits">2</td><td class="source">      legacyTheme = false;</td></tr><tr class="hit"><td class="line">240</td><td class="hits">2</td><td class="source">      themes.forEach(function(theme) {</td></tr><tr class="hit"><td class="line">241</td><td class="hits">2</td><td class="source">        if (theme === &quot;theme.json&quot;) {</td></tr><tr class="miss"><td class="line">242</td><td class="hits">0</td><td class="source">          legacyTheme = true;</td></tr><tr class="miss"><td class="line">243</td><td class="hits">0</td><td class="source">          console.log(&quot;Themes are now stored in sub-folders under the themes folder, please move: &quot; + folder + &quot; (e.g. to custom/&quot; + folder + &quot;).\r\n&quot;);</td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">247</td><td class="hits"></td><td class="source">      // Process</td></tr><tr class="hit"><td class="line">248</td><td class="hits">2</td><td class="source">      if (!legacyTheme) {</td></tr><tr class="hit"><td class="line">249</td><td class="hits">2</td><td class="source">        themes.forEach(function(theme) {</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">251</td><td class="hits">4</td><td class="source">          if (theme != &quot;README&quot; &amp;&amp; theme != '.DS_Store') themePath = calipso.lib.path.join(rootpath, themeBasePath, folder, theme);</td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">          // Create the theme object</td></tr><tr class="hit"><td class="line">253</td><td class="hits">2</td><td class="source">          calipso.availableThemes[theme] = {</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source">            name: theme,</td></tr><tr><td class="line">255</td><td class="hits"></td><td class="source">            path: themePath</td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source">          };</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">          // Load the about info from package.json</td></tr><tr class="hit"><td class="line">258</td><td class="hits">2</td><td class="source">          calipso.module.loadAbout(calipso.availableThemes[theme], themePath, 'theme.json');</td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">265</td><td class="hits">2</td><td class="source">  next();</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source"> * Configure a theme using the theme library.</td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">273</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">274</td><td class="hits">1</td><td class="source">function configureTheme(next, overrideTheme) {</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">276</td><td class="hits">2</td><td class="source">  var defaultTheme = calipso.config.get(&quot;theme:default&quot;);</td></tr><tr class="hit"><td class="line">277</td><td class="hits">2</td><td class="source">  var themeName = overrideTheme ? overrideTheme : calipso.config.get('theme:front');</td></tr><tr class="hit"><td class="line">278</td><td class="hits">2</td><td class="source">  var themeConfig = calipso.availableThemes[themeName]; // Reference to theme.json</td></tr><tr class="hit"><td class="line">279</td><td class="hits">2</td><td class="source">  if (themeConfig) {</td></tr><tr><td class="line">280</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">281</td><td class="hits"></td><td class="source">    // Themes is the library</td></tr><tr class="hit"><td class="line">282</td><td class="hits">2</td><td class="source">    calipso.themes.Theme(themeConfig, function(err, loadedTheme) {</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">      // Current theme is always in calipso.theme</td></tr><tr class="hit"><td class="line">285</td><td class="hits">2</td><td class="source">      calipso.theme = loadedTheme;</td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">287</td><td class="hits">2</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">288</td><td class="hits">0</td><td class="source">        calipso.error(err.message);</td></tr><tr><td class="line">289</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">291</td><td class="hits">2</td><td class="source">      if (!calipso.theme) {</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">293</td><td class="hits">0</td><td class="source">        if (loadedTheme.name === defaultTheme) {</td></tr><tr class="miss"><td class="line">294</td><td class="hits">0</td><td class="source">          calipso.error('There has been a failure loading the default theme, calipso cannot start until this is fixed, terminating.');</td></tr><tr class="miss"><td class="line">295</td><td class="hits">0</td><td class="source">          process.exit();</td></tr><tr class="miss"><td class="line">296</td><td class="hits">0</td><td class="source">          return;</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">298</td><td class="hits">0</td><td class="source">          calipso.error('The `' + themeName + '` theme failed to load, attempting to use the default theme: `' + defaultTheme + '`');</td></tr><tr class="miss"><td class="line">299</td><td class="hits">0</td><td class="source">          configureTheme(next, defaultTheme);</td></tr><tr class="miss"><td class="line">300</td><td class="hits">0</td><td class="source">          return;</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">302</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source">      } else {</td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">305</td><td class="hits"></td><td class="source">        // Search for middleware that already has themeStatic tag</td></tr><tr class="hit"><td class="line">306</td><td class="hits">2</td><td class="source">        var foundMiddleware = false,</td></tr><tr><td class="line">307</td><td class="hits"></td><td class="source">          mw;</td></tr><tr class="hit"><td class="line">308</td><td class="hits">2</td><td class="source">        calipso.app.stack.forEach(function(middleware, key) {</td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">310</td><td class="hits">6</td><td class="source">          if (middleware.handle.tag === 'theme.stylus') {</td></tr><tr class="hit"><td class="line">311</td><td class="hits">1</td><td class="source">            foundMiddleware = true;</td></tr><tr class="hit"><td class="line">312</td><td class="hits">1</td><td class="source">            mw = calipso.app.mwHelpers.stylusMiddleware(themeConfig.path);</td></tr><tr class="hit"><td class="line">313</td><td class="hits">1</td><td class="source">            calipso.app.stack[key].handle = mw;</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">315</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">316</td><td class="hits">6</td><td class="source">          if (middleware.handle.tag === 'theme.static') {</td></tr><tr class="hit"><td class="line">317</td><td class="hits">1</td><td class="source">            foundMiddleware = true;</td></tr><tr class="hit"><td class="line">318</td><td class="hits">1</td><td class="source">            mw = calipso.app.mwHelpers.staticMiddleware(themeConfig.path);</td></tr><tr class="hit"><td class="line">319</td><td class="hits">1</td><td class="source">            calipso.app.stack[key].handle = mw;</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">322</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">323</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">324</td><td class="hits">2</td><td class="source">        next();</td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">330</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">332</td><td class="hits">0</td><td class="source">    if (themeName === defaultTheme) {</td></tr><tr class="miss"><td class="line">333</td><td class="hits">0</td><td class="source">      console.error(&quot;Unable to locate the theme: &quot; + themeName + &quot;, terminating.&quot;);</td></tr><tr class="miss"><td class="line">334</td><td class="hits">0</td><td class="source">      process.exit();</td></tr><tr><td class="line">335</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">336</td><td class="hits">0</td><td class="source">      calipso.error('The `' + themeName + '` theme is missing, trying the defaul theme: `' + defaultTheme + '`');</td></tr><tr class="miss"><td class="line">337</td><td class="hits">0</td><td class="source">      configureTheme(next, defaultTheme);</td></tr><tr><td class="line">338</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">341</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">342</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Blocks.js">core/Blocks.js</h2><div id="stats" class="medium"><div class="percentage">70%</div><div class="sloc">30</div><div class="hits">21</div><div class="misses">9</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Library - Storage of Rendered Blocks</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * This class controls the storage and retrieval of blocks rendered via the Router, e.g. specific pieces of output.</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">10</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * Holder for rendered blocks (get / set)</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * Idea is that this will give us an opportunity</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> * to cache expensive sections of a page.</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">1</td><td class="source">function RenderedBlocks(cache) {</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">  // Store the content rendered by modules</td></tr><tr class="hit"><td class="line">23</td><td class="hits">1</td><td class="source">  this.content = {};</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">  // Flags to indicate if it should be cached</td></tr><tr class="hit"><td class="line">26</td><td class="hits">1</td><td class="source">  this.contentCache = {};</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">  // The cache itself</td></tr><tr class="hit"><td class="line">29</td><td class="hits">1</td><td class="source">  this.cache = cache;</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> * Set block content</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">36</td><td class="hits">1</td><td class="source">RenderedBlocks.prototype.set = function(block, content, layout, params, next) {</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">38</td><td class="hits">1</td><td class="source">  var cacheKey = calipso.cacheService.getCacheKey(['block', block], params);</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">40</td><td class="hits">1</td><td class="source">  this.content[block] = this.content[block] || [];</td></tr><tr class="hit"><td class="line">41</td><td class="hits">1</td><td class="source">  this.content[block].push(content);</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">  // If we are caching, then cache it.</td></tr><tr class="hit"><td class="line">44</td><td class="hits">1</td><td class="source">  if (this.contentCache[block]) {</td></tr><tr class="miss"><td class="line">45</td><td class="hits">0</td><td class="source">    calipso.silly(&quot;Cache set for &quot; + cacheKey);</td></tr><tr class="miss"><td class="line">46</td><td class="hits">0</td><td class="source">    this.cache.set(cacheKey, {</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">      content: content,</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">      layout: layout</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">    }, null, next);</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="hit"><td class="line">51</td><td class="hits">1</td><td class="source">    next();</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source"> * Get block content</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">RenderedBlocks.prototype.get = function(key, next) {</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">  // Check to see if the key is a regex, for 0.4 and 0.5 nodej</td></tr><tr class="hit"><td class="line">62</td><td class="hits">8</td><td class="source">  if (typeof key === 'object' || typeof key === &quot;function&quot;) {</td></tr><tr class="hit"><td class="line">63</td><td class="hits">8</td><td class="source">    var item, items = [];</td></tr><tr class="hit"><td class="line">64</td><td class="hits">8</td><td class="source">    for (item in this.content) {</td></tr><tr class="hit"><td class="line">65</td><td class="hits">3</td><td class="source">      if (this.content.hasOwnProperty(item)) {</td></tr><tr class="hit"><td class="line">66</td><td class="hits">3</td><td class="source">        if (item.match(key)) {</td></tr><tr class="hit"><td class="line">67</td><td class="hits">1</td><td class="source">          items.push(this.content[item]);</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">71</td><td class="hits">8</td><td class="source">    next(null, items);</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">73</td><td class="hits">0</td><td class="source">    next(null, this.content[key] || []);</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> * Get content from cache and load into block</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">81</td><td class="hits">1</td><td class="source">RenderedBlocks.prototype.getCache = function(key, block, next) {</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">83</td><td class="hits">0</td><td class="source">  calipso.silly(&quot;Cache hit for block &quot; + key);</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">85</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr class="miss"><td class="line">86</td><td class="hits">0</td><td class="source">  this.cache.get(key, function(err, cache) {</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">88</td><td class="hits">0</td><td class="source">    self.content[block] = self.content[block] || [];</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">    self.content[block].push(cache.content);</td></tr><tr class="miss"><td class="line">90</td><td class="hits">0</td><td class="source">    next(err, cache.layout);</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">96</td><td class="hits">1</td><td class="source">module.exports.RenderedBlocks = RenderedBlocks;</td></tr></tbody></table></div><div class="file"><h2 id="core/Cache.js">core/Cache.js</h2><div id="stats" class="high"><div class="percentage">100%</div><div class="sloc">7</div><div class="hits">7</div><div class="misses">0</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Caching Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * This is the core Calipso library that enables caching to be turned on</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * that will cache both module and full page output.</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * The idea is to have a pluggable cache storage module, copied liberally</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> * from concepts behind the express session module.</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">16</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  MemoryStore = require('./cacheAdapters/memory'),</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">  Store = require('./cacheAdapters/store');</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">// Exports</td></tr><tr class="hit"><td class="line">23</td><td class="hits">1</td><td class="source">exports.Cache = Cache;</td></tr><tr class="hit"><td class="line">24</td><td class="hits">1</td><td class="source">exports.Store = Store;</td></tr><tr class="hit"><td class="line">25</td><td class="hits">1</td><td class="source">exports.MemoryStore = MemoryStore;</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> * Very simple wrapper that</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> * Enables pluggability of cache store, defaulting to in Memory</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> *    cache.set('cc','RAH!',500,function() {</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> *       cache.get('cc',function(err,item) {</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> *         console.log(item);</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> *       });</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> *    });</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">39</td><td class="hits">1</td><td class="source">function Cache(options) {</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">41</td><td class="hits">1</td><td class="source">  var options = options || {},</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">    store = store || new MemoryStore(options);</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">44</td><td class="hits">1</td><td class="source">  return store;</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/cacheAdapters/memory.js">core/cacheAdapters/memory.js</h2><div id="stats" class="low"><div class="percentage">30%</div><div class="sloc">39</div><div class="hits">12</div><div class="misses">27</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Calipso - cache - Memory Store</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Approach copied from Connect session store</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * Module dependencies.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">12</td><td class="hits">1</td><td class="source">var Store = require('./store');</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * Initialize a new `MemoryStore`.</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">1</td><td class="source">var MemoryStore = module.exports = function MemoryStore(options) {</td></tr><tr class="hit"><td class="line">21</td><td class="hits">1</td><td class="source">  this.cache = {};</td></tr><tr class="hit"><td class="line">22</td><td class="hits">1</td><td class="source">  this.options = options || {};</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> * Inherit from `Store.prototype`.</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">28</td><td class="hits">1</td><td class="source">MemoryStore.prototype.__proto__ = Store.prototype;</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> * Attempt to fetch cache by the given `key'.</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> * @param {String} key</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">38</td><td class="hits">1</td><td class="source">MemoryStore.prototype.get = function(key, fn){</td></tr><tr class="miss"><td class="line">39</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">  //process.nextTick(function(){</td></tr><tr class="miss"><td class="line">42</td><td class="hits">0</td><td class="source">    var cache = self.cache[key];</td></tr><tr class="miss"><td class="line">43</td><td class="hits">0</td><td class="source">    if (cache) {</td></tr><tr class="miss"><td class="line">44</td><td class="hits">0</td><td class="source">      fn(null, cache.item);</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">46</td><td class="hits">0</td><td class="source">      fn(new Error('Cache miss: ' + key));</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">  //});</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> * Check cache by the given `key'.</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> * @param {String} key</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">MemoryStore.prototype.check = function(key, fn){</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">61</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr class="miss"><td class="line">62</td><td class="hits">0</td><td class="source">  var cache = self.cache[key];</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">64</td><td class="hits">0</td><td class="source">  if (cache) {</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">    // Check to see if it has expired</td></tr><tr class="miss"><td class="line">66</td><td class="hits">0</td><td class="source">    if (!cache.expires || Date.now() &lt; cache.expires) { // TODO</td></tr><tr class="miss"><td class="line">67</td><td class="hits">0</td><td class="source">      fn(null, true);</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">69</td><td class="hits">0</td><td class="source">      self.destroy(key, fn);</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">72</td><td class="hits">0</td><td class="source">    fn(null,false);</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> * Add an item to the cache, referenced by key</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> * with expires</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> * @param {String} key</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> * @param {String} item</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source"> * @param {Number} expires (milliseconds)</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">88</td><td class="hits">1</td><td class="source">MemoryStore.prototype.set = function(key, item, ttl, fn){</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">  //process.nextTick(function(){</td></tr><tr class="miss"><td class="line">91</td><td class="hits">0</td><td class="source">    ttl = ttl || (self.options.ttl || 600);</td></tr><tr class="miss"><td class="line">92</td><td class="hits">0</td><td class="source">    var expires = Date.now() + ttl;</td></tr><tr class="miss"><td class="line">93</td><td class="hits">0</td><td class="source">    self.cache[key] = {item:item, expires:expires}</td></tr><tr class="miss"><td class="line">94</td><td class="hits">0</td><td class="source">    fn &amp;&amp; fn();</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source">  //});</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> * Destroy the session associated with the given `key`.</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> * @param {String} key</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">105</td><td class="hits">1</td><td class="source">MemoryStore.prototype.destroy = function(key, fn){</td></tr><tr class="miss"><td class="line">106</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">  //process.nextTick(function(){</td></tr><tr class="miss"><td class="line">108</td><td class="hits">0</td><td class="source">    delete self.cache[key];</td></tr><tr class="miss"><td class="line">109</td><td class="hits">0</td><td class="source">    fn &amp;&amp; fn();</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">  //});</td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source"> * Invoke the given callback `fn` with all active sessions.</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">120</td><td class="hits">1</td><td class="source">MemoryStore.prototype.all = function(fn){</td></tr><tr class="miss"><td class="line">121</td><td class="hits">0</td><td class="source">  var arr = []</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">    , keys = Object.keys(this.cache);</td></tr><tr class="miss"><td class="line">123</td><td class="hits">0</td><td class="source">  for (var i = 0, len = keys.length; i &lt; len; ++i) {</td></tr><tr class="miss"><td class="line">124</td><td class="hits">0</td><td class="source">    arr.push(this.cache[keys[i]]);</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">  }</td></tr><tr class="miss"><td class="line">126</td><td class="hits">0</td><td class="source">  fn(null, arr);</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source"> * Clear cache</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">136</td><td class="hits">1</td><td class="source">MemoryStore.prototype.clear = function(fn){</td></tr><tr class="miss"><td class="line">137</td><td class="hits">0</td><td class="source">  this.cache = {};</td></tr><tr class="miss"><td class="line">138</td><td class="hits">0</td><td class="source">  fn &amp;&amp; fn();</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> * Fetch number of cache items</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source"> * @param {Function} fn</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source"> * @api public</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">148</td><td class="hits">1</td><td class="source">MemoryStore.prototype.length = function(fn){</td></tr><tr class="miss"><td class="line">149</td><td class="hits">0</td><td class="source">  fn(null, Object.keys(this.cache).length);</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/cacheAdapters/store.js">core/cacheAdapters/store.js</h2><div id="stats" class="high"><div class="percentage">75%</div><div class="sloc">16</div><div class="hits">12</div><div class="misses">4</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Calipso - cache - Store</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Concepts taken from connect session</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * Initialize abstract `Store`.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> * @api private</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">13</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', '..', 'calipso'));</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> * Store object - options:</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> * prefix - a prefix to attach to all cache keys, defaults to calipso.</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">21</td><td class="hits">1</td><td class="source">var Store = module.exports = function Store(options){</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">23</td><td class="hits">0</td><td class="source">  this.options = options || {};</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">* Generate a cache key - applies to all store types</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">*/</td></tr><tr class="hit"><td class="line">30</td><td class="hits">1</td><td class="source">Store.prototype.getCacheKey = function(keys, params) {</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">32</td><td class="hits">1</td><td class="source">   var prefix = this.options.prefix || &quot;calipso&quot;;</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">   // Append the theme, allows for theme change</td></tr><tr class="hit"><td class="line">35</td><td class="hits">1</td><td class="source">   var cacheKey = prefix + &quot;::&quot; + calipso.theme.theme, paramCount = 0;</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">   // Create the key from the keys</td></tr><tr class="hit"><td class="line">38</td><td class="hits">1</td><td class="source">   keys.forEach(function(value) {</td></tr><tr class="hit"><td class="line">39</td><td class="hits">2</td><td class="source">    cacheKey += &quot;::&quot; + value;</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">   })</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">42</td><td class="hits">1</td><td class="source">   var qs = require(&quot;querystring&quot;);</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">44</td><td class="hits">1</td><td class="source">   if(params) {</td></tr><tr class="hit"><td class="line">45</td><td class="hits">1</td><td class="source">     cacheKey += &quot;::&quot;;</td></tr><tr class="hit"><td class="line">46</td><td class="hits">1</td><td class="source">     calipso.lib._.each(params,function(param,key) {</td></tr><tr class="miss"><td class="line">47</td><td class="hits">0</td><td class="source">        if(param) {</td></tr><tr class="miss"><td class="line">48</td><td class="hits">0</td><td class="source">          cacheKey += (paramCount &gt; 0 ? &quot;::&quot; : &quot;&quot;) + (param ? (key + &quot;=&quot; + qs.escape(param)) : &quot;&quot;);</td></tr><tr class="miss"><td class="line">49</td><td class="hits">0</td><td class="source">          paramCount += 1;</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">     });</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">   }</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">54</td><td class="hits">1</td><td class="source">   return cacheKey;</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Config.js">core/Config.js</h2><div id="stats" class="high"><div class="percentage">96%</div><div class="sloc">57</div><div class="hits">55</div><div class="misses">2</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Configuration library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">5</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source">  step = require('step'),</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source">  _ = require('underscore'),</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source">  fs = require('fs');</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> * Config object, wrapper for nconf</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> *  @type</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> *  @options</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">17</td><td class="hits">1</td><td class="source">function Config(options) {</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  // Defaults</td></tr><tr class="hit"><td class="line">20</td><td class="hits">9</td><td class="source">  this.type = options &amp;&amp; options.type ? options.type : 'file';</td></tr><tr class="hit"><td class="line">21</td><td class="hits">9</td><td class="source">  this.env = options &amp;&amp; options.env ? options.env : (process.env.NODE_ENV || 'development');</td></tr><tr class="hit"><td class="line">22</td><td class="hits">9</td><td class="source">  this.path = options &amp;&amp; options.path ? options.path : path.join(rootpath, 'conf');</td></tr><tr class="hit"><td class="line">23</td><td class="hits">9</td><td class="source">  this.defaultConfig = options &amp;&amp; options.defaultConfig ? options.defaultConfig : path.join(rootpath, 'lib', 'conf', 'default.json');</td></tr><tr class="hit"><td class="line">24</td><td class="hits">9</td><td class="source">  this.file = path.join(this.path, this.env + '.json');</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">  // Track if changes have been made to config</td></tr><tr class="hit"><td class="line">27</td><td class="hits">9</td><td class="source">  this.dirty = false;</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">31</td><td class="hits">1</td><td class="source">Config.prototype.init = function(next) {</td></tr><tr class="hit"><td class="line">32</td><td class="hits">8</td><td class="source">  if (typeof next !== 'function') next = function(err) {</td></tr><tr class="miss"><td class="line">33</td><td class="hits">0</td><td class="source">    if (err) console.error(err.message)</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  };</td></tr><tr class="hit"><td class="line">35</td><td class="hits">8</td><td class="source">  this.nconf = new require('nconf');</td></tr><tr class="hit"><td class="line">36</td><td class="hits">8</td><td class="source">  this.load(next);</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> * Check to see if configuration for this environment</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> * doesn't exist, if so, it loads the default from default.json.</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">43</td><td class="hits">1</td><td class="source">Config.prototype.check = function() {</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">45</td><td class="hits">9</td><td class="source">  if (!path.existsSync(this.file)) {</td></tr><tr class="hit"><td class="line">46</td><td class="hits">6</td><td class="source">    try {</td></tr><tr class="hit"><td class="line">47</td><td class="hits">6</td><td class="source">      var defaultFile = fs.readFileSync(this.defaultConfig);</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">      // Parse it to make sure there are no errors</td></tr><tr class="hit"><td class="line">49</td><td class="hits">5</td><td class="source">      defaultFile = JSON.stringify(JSON.parse(defaultFile), true);</td></tr><tr class="hit"><td class="line">50</td><td class="hits">5</td><td class="source">      fs.writeFileSync(this.file, defaultFile);</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">    } catch (ex) {</td></tr><tr class="hit"><td class="line">52</td><td class="hits">1</td><td class="source">      return ex.message;</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">54</td><td class="hits">5</td><td class="source">    return;</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="hit"><td class="line">56</td><td class="hits">3</td><td class="source">    return;</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> * Load the configuration</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">64</td><td class="hits">1</td><td class="source">Config.prototype.load = function(next) {</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">  // Check if config exists for this environment or default it</td></tr><tr class="hit"><td class="line">67</td><td class="hits">9</td><td class="source">  var checkConfig = this.check();</td></tr><tr class="hit"><td class="line">68</td><td class="hits">9</td><td class="source">  if (!checkConfig) {</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    // Initialise nconf</td></tr><tr class="hit"><td class="line">71</td><td class="hits">8</td><td class="source">    try {</td></tr><tr class="hit"><td class="line">72</td><td class="hits">8</td><td class="source">      this.nconf.use(this.type, this);</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">    } catch (ex) {</td></tr><tr class="miss"><td class="line">74</td><td class="hits">0</td><td class="source">      return next(ex);</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">77</td><td class="hits">8</td><td class="source">    this.nconf.load(next);</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">81</td><td class="hits">1</td><td class="source">    next(new Error(&quot;Unable to load configuration defined in &quot; + this.env + &quot;.json, there may be a problem with the default configuration in &quot; + this.defaultConfig + &quot;, reason: &quot; + checkConfig));</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source"> * Get config - wrapper</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">90</td><td class="hits">1</td><td class="source">Config.prototype.get = function(key) {</td></tr><tr class="hit"><td class="line">91</td><td class="hits">107</td><td class="source">  return this.nconf.get(key);</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> * Get config for module - wrapper</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">97</td><td class="hits">1</td><td class="source">Config.prototype.getModuleConfig = function(moduleName, key) {</td></tr><tr class="hit"><td class="line">98</td><td class="hits">2</td><td class="source">  var moduleKey = 'modules:' + moduleName + ':config' + (key ? ':' + key : '');</td></tr><tr class="hit"><td class="line">99</td><td class="hits">2</td><td class="source">  return this.nconf.get(moduleKey);</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> * Set config</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">106</td><td class="hits">1</td><td class="source">Config.prototype.set = function(key, value) {</td></tr><tr class="hit"><td class="line">107</td><td class="hits">9</td><td class="source">  this.dirty = true;</td></tr><tr class="hit"><td class="line">108</td><td class="hits">9</td><td class="source">  this.nconf.set(key, value);</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source"> * Set config for module - wrapper</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">114</td><td class="hits">1</td><td class="source">Config.prototype.setModuleConfig = function(moduleName, key, value) {</td></tr><tr class="hit"><td class="line">115</td><td class="hits">1</td><td class="source">  var moduleKey = 'modules:' + moduleName + ':config' + (key ? ':' + key : '');</td></tr><tr class="hit"><td class="line">116</td><td class="hits">1</td><td class="source">  this.dirty = true;</td></tr><tr class="hit"><td class="line">117</td><td class="hits">1</td><td class="source">  this.nconf.set(moduleKey, value);</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source"> * Set default config for module - wrapper</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">123</td><td class="hits">1</td><td class="source">Config.prototype.setDefaultModuleConfig = function(moduleName, config) {</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">125</td><td class="hits">1</td><td class="source">  var moduleKey = 'modules:' + moduleName + ':config';</td></tr><tr class="hit"><td class="line">126</td><td class="hits">1</td><td class="source">  this.dirty = true;</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">  // Extract the defaults from the config  </td></tr><tr class="hit"><td class="line">129</td><td class="hits">1</td><td class="source">  var defaultConfig = _.reduce(_.keys(config), function(memo, key) {</td></tr><tr class="hit"><td class="line">130</td><td class="hits">1</td><td class="source">    memo[key] = config[key].</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">  default;</td></tr><tr class="hit"><td class="line">132</td><td class="hits">1</td><td class="source">    return memo;</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">  }, {})</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">135</td><td class="hits">1</td><td class="source">  this.nconf.set(moduleKey, defaultConfig);</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source"> * Save config</td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">142</td><td class="hits">1</td><td class="source">Config.prototype.save = function(next) {</td></tr><tr class="hit"><td class="line">143</td><td class="hits">2</td><td class="source">  this.dirty = false;</td></tr><tr class="hit"><td class="line">144</td><td class="hits">2</td><td class="source">  this.nconf.save(next);</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source"> * Set &amp; save config</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">151</td><td class="hits">1</td><td class="source">Config.prototype.setSave = function(key, value, next) {</td></tr><tr class="hit"><td class="line">152</td><td class="hits">1</td><td class="source">  this.set(key, value);</td></tr><tr class="hit"><td class="line">153</td><td class="hits">1</td><td class="source">  this.dirty = false;</td></tr><tr class="hit"><td class="line">154</td><td class="hits">1</td><td class="source">  this.save(next);</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source"> * Export the config object</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">160</td><td class="hits">1</td><td class="source">module.exports = Config;</td></tr></tbody></table></div><div class="file"><h2 id="core/Date.js">core/Date.js</h2><div id="stats" class="terrible"><div class="percentage">13%</div><div class="sloc">149</div><div class="hits">20</div><div class="misses">129</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * This is a generic date parsing and formatting library, to avoid any confusion</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * about how dates are handled across both the back and front end (assuming jQuery UI will be)</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * the default.</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * These functions are extracted from the jQuery UI Datepicker (see below).</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * jQuery UI Datepicker</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> * Dual licensed under the MIT or GPL Version 2 licenses.</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * - License http://jquery.org/license</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * - Original Source http://docs.jquery.com/UI/Datepicker</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">19</td><td class="hits">1</td><td class="source">function CalipsoDate() {</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">21</td><td class="hits">1</td><td class="source">  this.regional = []; // Available regional settings, indexed by language code</td></tr><tr class="hit"><td class="line">22</td><td class="hits">1</td><td class="source">  this.regional[''] = { // Default regional settings</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">    closeText: 'Done',</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">    // Display text for close link</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">    prevText: 'Prev',</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">    // Display text for previous month link</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">    nextText: 'Next',</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">    // Display text for next month link</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">    currentText: 'Today',</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">    // Display text for current month link</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">    monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">    // Names of months for drop-down and formatting</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">    monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">    // For formatting</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">    dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">    // For formatting</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">    dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">    // For formatting</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">    dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">    // Column headings for days starting at Sunday</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">    weekHeader: 'Wk',</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">    // Column header for week of the year</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">    dateFormat: 'mm/dd/yy',</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">    // See format options on parseDate</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">    firstDay: 0,</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">    // The first day of the week, Sun = 0, Mon = 1, ...</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">    isRTL: false,</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">    // True if right-to-left language, false if left-to-right</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">    showMonthAfterYear: false,</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">    // True if the year select precedes month, false for month then year</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">    yearSuffix: '' // Additional text to append to the year in the month headers</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">54</td><td class="hits">1</td><td class="source">  this._defaults = this.regional[''];</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">  // Standard date formats.</td></tr><tr class="hit"><td class="line">57</td><td class="hits">1</td><td class="source">  this.ATOM = 'yy-mm-dd'; // RFC 3339 (ISO 8601)</td></tr><tr class="hit"><td class="line">58</td><td class="hits">1</td><td class="source">  this.COOKIE = 'D, dd M yy';</td></tr><tr class="hit"><td class="line">59</td><td class="hits">1</td><td class="source">  this.ISO_8601 = 'yy-mm-dd';</td></tr><tr class="hit"><td class="line">60</td><td class="hits">1</td><td class="source">  this.RFC_822 = 'D, d M y';</td></tr><tr class="hit"><td class="line">61</td><td class="hits">1</td><td class="source">  this.RFC_850 = 'DD, dd-M-y';</td></tr><tr class="hit"><td class="line">62</td><td class="hits">1</td><td class="source">  this.RFC_1036 = 'D, d M y';</td></tr><tr class="hit"><td class="line">63</td><td class="hits">1</td><td class="source">  this.RFC_1123 = 'D, d M yy';</td></tr><tr class="hit"><td class="line">64</td><td class="hits">1</td><td class="source">  this.RFC_2822 = 'D, d M yy';</td></tr><tr class="hit"><td class="line">65</td><td class="hits">1</td><td class="source">  this.RSS = 'D, d M y'; // RFC 822</td></tr><tr class="hit"><td class="line">66</td><td class="hits">1</td><td class="source">  this.TICKS = '!';</td></tr><tr class="hit"><td class="line">67</td><td class="hits">1</td><td class="source">  this.TIMESTAMP = '@';</td></tr><tr class="hit"><td class="line">68</td><td class="hits">1</td><td class="source">  this.W3C = 'yy-mm-dd'; // ISO 8601</td></tr><tr class="hit"><td class="line">69</td><td class="hits">1</td><td class="source">  this._ticksTo1970 = (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000);</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">/* Parse a string value into a date object.</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">     See formatDate below for the possible formats.</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">     @param  format    string - the expected format of the date</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">     @param  value     string - the date in the above format</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source">     @param  settings  Object - attributes include:</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">                       shortYearCutoff  number - the cutoff year for determining the century (optional)</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">                       dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">                       dayNames         string[7] - names of the days from Sunday (optional)</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">                       monthNamesShort  string[12] - abbreviated names of the months (optional)</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">                       monthNames       string[12] - names of the months (optional)</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">     @return  Date - the extracted date value or null if value is blank */</td></tr><tr class="hit"><td class="line">85</td><td class="hits">1</td><td class="source">CalipsoDate.prototype.parseDate = function(format, value, settings) {</td></tr><tr class="miss"><td class="line">86</td><td class="hits">0</td><td class="source">  if (format == null || value == null) throw 'Invalid arguments';</td></tr><tr class="miss"><td class="line">87</td><td class="hits">0</td><td class="source">  value = (typeof value == 'object' ? value.toString() : value + '');</td></tr><tr class="miss"><td class="line">88</td><td class="hits">0</td><td class="source">  if (value == '') return null;</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">  var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;</td></tr><tr class="miss"><td class="line">90</td><td class="hits">0</td><td class="source">  shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));</td></tr><tr class="miss"><td class="line">91</td><td class="hits">0</td><td class="source">  var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;</td></tr><tr class="miss"><td class="line">92</td><td class="hits">0</td><td class="source">  var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;</td></tr><tr class="miss"><td class="line">93</td><td class="hits">0</td><td class="source">  var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;</td></tr><tr class="miss"><td class="line">94</td><td class="hits">0</td><td class="source">  var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;</td></tr><tr class="miss"><td class="line">95</td><td class="hits">0</td><td class="source">  var year = -1;</td></tr><tr class="miss"><td class="line">96</td><td class="hits">0</td><td class="source">  var month = -1;</td></tr><tr class="miss"><td class="line">97</td><td class="hits">0</td><td class="source">  var day = -1;</td></tr><tr class="miss"><td class="line">98</td><td class="hits">0</td><td class="source">  var doy = -1;</td></tr><tr class="miss"><td class="line">99</td><td class="hits">0</td><td class="source">  var literal = false;</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">  // Check whether a format character is doubled</td></tr><tr class="miss"><td class="line">101</td><td class="hits">0</td><td class="source">  var lookAhead = function(match) {</td></tr><tr class="miss"><td class="line">102</td><td class="hits">0</td><td class="source">      var matches = (iFormat + 1 &lt; format.length &amp;&amp; format.charAt(iFormat + 1) == match);</td></tr><tr class="miss"><td class="line">103</td><td class="hits">0</td><td class="source">      if (matches) iFormat++;</td></tr><tr class="miss"><td class="line">104</td><td class="hits">0</td><td class="source">      return matches;</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">  // Extract a number from the string value</td></tr><tr class="miss"><td class="line">107</td><td class="hits">0</td><td class="source">  var getNumber = function(match) {</td></tr><tr class="miss"><td class="line">108</td><td class="hits">0</td><td class="source">      var isDoubled = lookAhead(match);</td></tr><tr class="miss"><td class="line">109</td><td class="hits">0</td><td class="source">      var size = (match == '@' ? 14 : (match == '!' ? 20 : (match == 'y' &amp;&amp; isDoubled ? 4 : (match == 'o' ? 3 : 2))));</td></tr><tr class="miss"><td class="line">110</td><td class="hits">0</td><td class="source">      var digits = new RegExp('^\\d{1,' + size + '}');</td></tr><tr class="miss"><td class="line">111</td><td class="hits">0</td><td class="source">      var num = value.substring(iValue).match(digits);</td></tr><tr class="miss"><td class="line">112</td><td class="hits">0</td><td class="source">      if (!num) throw 'Missing number at position ' + iValue;</td></tr><tr class="miss"><td class="line">113</td><td class="hits">0</td><td class="source">      iValue += num[0].length;</td></tr><tr class="miss"><td class="line">114</td><td class="hits">0</td><td class="source">      return parseInt(num[0], 10);</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">  // Extract a name from the string value and convert to an index</td></tr><tr class="miss"><td class="line">117</td><td class="hits">0</td><td class="source">  var getName = function(match, shortNames, longNames) {</td></tr><tr class="miss"><td class="line">118</td><td class="hits">0</td><td class="source">      var names = $.map(lookAhead(match) ? longNames : shortNames, function(v, k) {</td></tr><tr class="miss"><td class="line">119</td><td class="hits">0</td><td class="source">        return [[k, v]];</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">      }).sort(function(a, b) {</td></tr><tr class="miss"><td class="line">121</td><td class="hits">0</td><td class="source">        return -(a[1].length - b[1].length);</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">      });</td></tr><tr class="miss"><td class="line">123</td><td class="hits">0</td><td class="source">      var index = -1;</td></tr><tr class="miss"><td class="line">124</td><td class="hits">0</td><td class="source">      $.each(names, function(i, pair) {</td></tr><tr class="miss"><td class="line">125</td><td class="hits">0</td><td class="source">        var name = pair[1];</td></tr><tr class="miss"><td class="line">126</td><td class="hits">0</td><td class="source">        if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {</td></tr><tr class="miss"><td class="line">127</td><td class="hits">0</td><td class="source">          index = pair[0];</td></tr><tr class="miss"><td class="line">128</td><td class="hits">0</td><td class="source">          iValue += name.length;</td></tr><tr class="miss"><td class="line">129</td><td class="hits">0</td><td class="source">          return false;</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">      });</td></tr><tr class="miss"><td class="line">132</td><td class="hits">0</td><td class="source">      if (index != -1) return index + 1;</td></tr><tr class="miss"><td class="line">133</td><td class="hits">0</td><td class="source">      else throw 'Unknown name at position ' + iValue;</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">  // Confirm that a literal character matches the string value</td></tr><tr class="miss"><td class="line">136</td><td class="hits">0</td><td class="source">  var checkLiteral = function() {</td></tr><tr class="miss"><td class="line">137</td><td class="hits">0</td><td class="source">      if (value.charAt(iValue) != format.charAt(iFormat)) throw 'Unexpected literal at position ' + iValue;</td></tr><tr class="miss"><td class="line">138</td><td class="hits">0</td><td class="source">      iValue++;</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">    };</td></tr><tr class="miss"><td class="line">140</td><td class="hits">0</td><td class="source">  var iValue = 0;</td></tr><tr class="miss"><td class="line">141</td><td class="hits">0</td><td class="source">  for (var iFormat = 0; iFormat &lt; format.length; iFormat++) {</td></tr><tr class="miss"><td class="line">142</td><td class="hits">0</td><td class="source">    if (literal) if (format.charAt(iFormat) == &quot;'&quot; &amp;&amp; !lookAhead(&quot;'&quot;)) literal = false;</td></tr><tr class="miss"><td class="line">143</td><td class="hits">0</td><td class="source">    else checkLiteral();</td></tr><tr class="miss"><td class="line">144</td><td class="hits">0</td><td class="source">    else switch (format.charAt(iFormat)) {</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">    case 'd':</td></tr><tr class="miss"><td class="line">146</td><td class="hits">0</td><td class="source">      day = getNumber('d');</td></tr><tr class="miss"><td class="line">147</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    case 'D':</td></tr><tr class="miss"><td class="line">149</td><td class="hits">0</td><td class="source">      getName('D', dayNamesShort, dayNames);</td></tr><tr class="miss"><td class="line">150</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source">    case 'o':</td></tr><tr class="miss"><td class="line">152</td><td class="hits">0</td><td class="source">      doy = getNumber('o');</td></tr><tr class="miss"><td class="line">153</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">    case 'm':</td></tr><tr class="miss"><td class="line">155</td><td class="hits">0</td><td class="source">      month = getNumber('m');</td></tr><tr class="miss"><td class="line">156</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">    case 'M':</td></tr><tr class="miss"><td class="line">158</td><td class="hits">0</td><td class="source">      month = getName('M', monthNamesShort, monthNames);</td></tr><tr class="miss"><td class="line">159</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source">    case 'y':</td></tr><tr class="miss"><td class="line">161</td><td class="hits">0</td><td class="source">      year = getNumber('y');</td></tr><tr class="miss"><td class="line">162</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    case '@':</td></tr><tr class="miss"><td class="line">164</td><td class="hits">0</td><td class="source">      var date = new Date(getNumber('@'));</td></tr><tr class="miss"><td class="line">165</td><td class="hits">0</td><td class="source">      year = date.getFullYear();</td></tr><tr class="miss"><td class="line">166</td><td class="hits">0</td><td class="source">      month = date.getMonth() + 1;</td></tr><tr class="miss"><td class="line">167</td><td class="hits">0</td><td class="source">      day = date.getDate();</td></tr><tr class="miss"><td class="line">168</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">    case '!':</td></tr><tr class="miss"><td class="line">170</td><td class="hits">0</td><td class="source">      var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);</td></tr><tr class="miss"><td class="line">171</td><td class="hits">0</td><td class="source">      year = date.getFullYear();</td></tr><tr class="miss"><td class="line">172</td><td class="hits">0</td><td class="source">      month = date.getMonth() + 1;</td></tr><tr class="miss"><td class="line">173</td><td class="hits">0</td><td class="source">      day = date.getDate();</td></tr><tr class="miss"><td class="line">174</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">    case &quot;'&quot;:</td></tr><tr class="miss"><td class="line">176</td><td class="hits">0</td><td class="source">      if (lookAhead(&quot;'&quot;)) checkLiteral();</td></tr><tr class="miss"><td class="line">177</td><td class="hits">0</td><td class="source">      else literal = true;</td></tr><tr class="miss"><td class="line">178</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">    default:</td></tr><tr class="miss"><td class="line">180</td><td class="hits">0</td><td class="source">      checkLiteral();</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">  }</td></tr><tr class="miss"><td class="line">183</td><td class="hits">0</td><td class="source">  if (year == -1) year = new Date().getFullYear();</td></tr><tr class="miss"><td class="line">184</td><td class="hits">0</td><td class="source">  else if (year &lt; 100) year += new Date().getFullYear() - new Date().getFullYear() % 100 + (year &lt;= shortYearCutoff ? 0 : -100);</td></tr><tr class="miss"><td class="line">185</td><td class="hits">0</td><td class="source">  if (doy &gt; -1) {</td></tr><tr class="miss"><td class="line">186</td><td class="hits">0</td><td class="source">    month = 1;</td></tr><tr class="miss"><td class="line">187</td><td class="hits">0</td><td class="source">    day = doy;</td></tr><tr class="miss"><td class="line">188</td><td class="hits">0</td><td class="source">    do {</td></tr><tr class="miss"><td class="line">189</td><td class="hits">0</td><td class="source">      var dim = this._getDaysInMonth(year, month - 1);</td></tr><tr class="miss"><td class="line">190</td><td class="hits">0</td><td class="source">      if (day &lt;= dim) break;</td></tr><tr class="miss"><td class="line">191</td><td class="hits">0</td><td class="source">      month++;</td></tr><tr class="miss"><td class="line">192</td><td class="hits">0</td><td class="source">      day -= dim;</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source">    } while (true);</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">  }</td></tr><tr class="miss"><td class="line">195</td><td class="hits">0</td><td class="source">  var date = this._daylightSavingAdjust(new Date(year, month - 1, day));</td></tr><tr class="miss"><td class="line">196</td><td class="hits">0</td><td class="source">  if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) throw 'Invalid date'; // E.g. 31/02/00</td></tr><tr class="miss"><td class="line">197</td><td class="hits">0</td><td class="source">  return date;</td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">/*</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">  Format a date object into a string value.</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">  The format can be combinations of the following</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">    d  - day of month (no leading zero)</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source">    dd - day of month (two digit)</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">    o  - day of year (no leading zeros)</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">    oo - day of year (three digit)</td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source">    D  - day name short</td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">    DD - day name long</td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">    m  - month of year (no leading zero)</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">    mm - month of year (two digit)</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source">    M  - month name short</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">    MM - month name long</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">    y  - year (two digit)</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">    yy - year (four digit)</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source">    @ - Unix timestamp (ms since 01/01/1970)</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">    ! - Windows ticks (100ns since 01/01/0001)</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">    '...' - literal text</td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source">    '' - single quote</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source">    @param  format    string - the desired format of the date</td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source">    @param  date      Date - the date value to format</td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source">    @param  settings  Object - attributes include:</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source">                      dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source">                      dayNames         string[7] - names of the days from Sunday (optional)</td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source">                      monthNamesShort  string[12] - abbreviated names of the months (optional)</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source">                      monthNames       string[12] - names of the months (optional)</td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">    @return  string - the date in the above format */</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">231</td><td class="hits">1</td><td class="source">CalipsoDate.prototype.formatDate = function(format, date, settings) {</td></tr><tr class="miss"><td class="line">232</td><td class="hits">0</td><td class="source">  if (!date) return '';</td></tr><tr class="miss"><td class="line">233</td><td class="hits">0</td><td class="source">  var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;</td></tr><tr class="miss"><td class="line">234</td><td class="hits">0</td><td class="source">  var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;</td></tr><tr class="miss"><td class="line">235</td><td class="hits">0</td><td class="source">  var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;</td></tr><tr class="miss"><td class="line">236</td><td class="hits">0</td><td class="source">  var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">  // Check whether a format character is doubled</td></tr><tr class="miss"><td class="line">238</td><td class="hits">0</td><td class="source">  var lookAhead = function(match) {</td></tr><tr class="miss"><td class="line">239</td><td class="hits">0</td><td class="source">      var matches = (iFormat + 1 &lt; format.length &amp;&amp; format.charAt(iFormat + 1) == match);</td></tr><tr class="miss"><td class="line">240</td><td class="hits">0</td><td class="source">      if (matches) iFormat++;</td></tr><tr class="miss"><td class="line">241</td><td class="hits">0</td><td class="source">      return matches;</td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source">  // Format a number, with leading zero if necessary</td></tr><tr class="miss"><td class="line">244</td><td class="hits">0</td><td class="source">  var formatNumber = function(match, value, len) {</td></tr><tr class="miss"><td class="line">245</td><td class="hits">0</td><td class="source">      var num = '' + value;</td></tr><tr class="miss"><td class="line">246</td><td class="hits">0</td><td class="source">      if (lookAhead(match)) while (num.length &lt; len)</td></tr><tr class="miss"><td class="line">247</td><td class="hits">0</td><td class="source">      num = '0' + num;</td></tr><tr class="miss"><td class="line">248</td><td class="hits">0</td><td class="source">      return num;</td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source">  // Format a name, short or long as requested</td></tr><tr class="miss"><td class="line">251</td><td class="hits">0</td><td class="source">  var formatName = function(match, value, shortNames, longNames) {</td></tr><tr class="miss"><td class="line">252</td><td class="hits">0</td><td class="source">      return (lookAhead(match) ? longNames[value] : shortNames[value]);</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">    };</td></tr><tr class="miss"><td class="line">254</td><td class="hits">0</td><td class="source">  var output = '';</td></tr><tr class="miss"><td class="line">255</td><td class="hits">0</td><td class="source">  var literal = false;</td></tr><tr class="miss"><td class="line">256</td><td class="hits">0</td><td class="source">  if (date) for (var iFormat = 0; iFormat &lt; format.length; iFormat++) {</td></tr><tr class="miss"><td class="line">257</td><td class="hits">0</td><td class="source">    if (literal) if (format.charAt(iFormat) == &quot;'&quot; &amp;&amp; !lookAhead(&quot;'&quot;)) literal = false;</td></tr><tr class="miss"><td class="line">258</td><td class="hits">0</td><td class="source">    else output += format.charAt(iFormat);</td></tr><tr class="miss"><td class="line">259</td><td class="hits">0</td><td class="source">    else switch (format.charAt(iFormat)) {</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">    case 'd':</td></tr><tr class="miss"><td class="line">261</td><td class="hits">0</td><td class="source">      output += formatNumber('d', date.getDate(), 2);</td></tr><tr class="miss"><td class="line">262</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">    case 'D':</td></tr><tr class="miss"><td class="line">264</td><td class="hits">0</td><td class="source">      output += formatName('D', date.getDay(), dayNamesShort, dayNames);</td></tr><tr class="miss"><td class="line">265</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source">    case 'o':</td></tr><tr class="miss"><td class="line">267</td><td class="hits">0</td><td class="source">      output += formatNumber('o', (date.getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000, 3);</td></tr><tr class="miss"><td class="line">268</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source">    case 'm':</td></tr><tr class="miss"><td class="line">270</td><td class="hits">0</td><td class="source">      output += formatNumber('m', date.getMonth() + 1, 2);</td></tr><tr class="miss"><td class="line">271</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source">    case 'M':</td></tr><tr class="miss"><td class="line">273</td><td class="hits">0</td><td class="source">      output += formatName('M', date.getMonth(), monthNamesShort, monthNames);</td></tr><tr class="miss"><td class="line">274</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source">    case 'y':</td></tr><tr class="miss"><td class="line">276</td><td class="hits">0</td><td class="source">      output += (lookAhead('y') ? date.getFullYear() : (date.getYear() % 100 &lt; 10 ? '0' : '') + date.getYear() % 100);</td></tr><tr class="miss"><td class="line">277</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source">    case '@':</td></tr><tr class="miss"><td class="line">279</td><td class="hits">0</td><td class="source">      output += date.getTime();</td></tr><tr class="miss"><td class="line">280</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">281</td><td class="hits"></td><td class="source">    case '!':</td></tr><tr class="miss"><td class="line">282</td><td class="hits">0</td><td class="source">      output += date.getTime() * 10000 + this._ticksTo1970;</td></tr><tr class="miss"><td class="line">283</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">    case &quot;'&quot;:</td></tr><tr class="miss"><td class="line">285</td><td class="hits">0</td><td class="source">      if (lookAhead(&quot;'&quot;)) output += &quot;'&quot;;</td></tr><tr class="miss"><td class="line">286</td><td class="hits">0</td><td class="source">      else literal = true;</td></tr><tr class="miss"><td class="line">287</td><td class="hits">0</td><td class="source">      break;</td></tr><tr><td class="line">288</td><td class="hits"></td><td class="source">    default:</td></tr><tr class="miss"><td class="line">289</td><td class="hits">0</td><td class="source">      output += format.charAt(iFormat);</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source">  }</td></tr><tr class="miss"><td class="line">292</td><td class="hits">0</td><td class="source">  return output;</td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">294</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">296</td><td class="hits"></td><td class="source"> * Export an instance of our date object</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">298</td><td class="hits">1</td><td class="source">module.exports = new CalipsoDate();</td></tr></tbody></table></div><div class="file"><h2 id="core/Event.js">core/Event.js</h2><div id="stats" class="high"><div class="percentage">95%</div><div class="sloc">132</div><div class="hits">126</div><div class="misses">6</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Module Event Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * This library provides an event emitter for modules that is created on each request,</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * to provide the ability for module dependencies to be managed, as well as enable modules</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * to ensure that they run after all other modules have emitted certain events (e.g. menu rendering).</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> * Includes</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">16</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">  util = require('util'),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  events = require('events'),</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">22</td><td class="hits">1</td><td class="source">exports = module.exports = {</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">  CalipsoEventEmitter: CalipsoEventEmitter,</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">  RequestEventListener: RequestEventListener,</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">  addModuleEventListener: addModuleEventListener,</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">  // Module &amp; Routing Event constants</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">  ROUTE_START: 'route_s',</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">  ROUTE_FINISH: 'route_f',</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">  INIT_START: 'init_s',</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">  INIT_FINISH: 'init_f'</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> * Calipso event emitter, object that enables calipso to emit events.</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> * Events are always triggered at server scope, and cannot be used to</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> * Execute functions in request scope</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">40</td><td class="hits">1</td><td class="source">function CalipsoEventEmitter(options) {</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">42</td><td class="hits">5</td><td class="source">  var self = this;</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">  // Initialise options</td></tr><tr class="hit"><td class="line">45</td><td class="hits">5</td><td class="source">  this.options = options || {};</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  // Create an emitter to drive events</td></tr><tr class="hit"><td class="line">48</td><td class="hits">5</td><td class="source">  this.emitter = new events.EventEmitter();</td></tr><tr class="hit"><td class="line">49</td><td class="hits">5</td><td class="source">  this.emitter.setMaxListeners(this.options.maxListeners || 100);</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">  // Holder for events, enable debugging of module events</td></tr><tr class="hit"><td class="line">52</td><td class="hits">5</td><td class="source">  this.events = {};</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">  // Clear all existing listeners</td></tr><tr class="hit"><td class="line">55</td><td class="hits">5</td><td class="source">  this.init = function() {</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">    // Clear down the event emitters</td></tr><tr class="hit"><td class="line">58</td><td class="hits">7</td><td class="source">    for (var event in self.events) {</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">60</td><td class="hits">3</td><td class="source">      self.emitter.removeAllListeners(&quot;PRE_&quot; + event);</td></tr><tr class="hit"><td class="line">61</td><td class="hits">3</td><td class="source">      self.emitter.removeAllListeners(&quot;POST_&quot; + event);</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">63</td><td class="hits">3</td><td class="source">      if (self.events[event].custom) {</td></tr><tr class="hit"><td class="line">64</td><td class="hits">3</td><td class="source">        for (var key in self.events[event].custom) {</td></tr><tr class="miss"><td class="line">65</td><td class="hits">0</td><td class="source">          self.emitter.removeAllListeners(event + &quot;_&quot; + key);</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">    // Add core events not created by modules</td></tr><tr class="hit"><td class="line">72</td><td class="hits">7</td><td class="source">    this.addEvent('FORM');</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">  // Wrapper for event emitter, enable turn on / off</td></tr><tr class="hit"><td class="line">77</td><td class="hits">5</td><td class="source">  this.addEvent = function(event, options) {</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">79</td><td class="hits">11</td><td class="source">    options = calipso.lib._.extend({</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">      enabled: true</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">    }, options);</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">83</td><td class="hits">11</td><td class="source">    this.events[event] = options;</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">    // Enable tracking of attached listeners for debugging purposes</td></tr><tr class="hit"><td class="line">85</td><td class="hits">11</td><td class="source">    this.events[event].preListeners = {</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">      '#': 0</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">    };</td></tr><tr class="hit"><td class="line">88</td><td class="hits">11</td><td class="source">    this.events[event].postListeners = {</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">      '#': 0</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">    };</td></tr><tr class="hit"><td class="line">91</td><td class="hits">11</td><td class="source">    this.events[event].custom = {};</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">  // Pre and post event prefixes</td></tr><tr class="hit"><td class="line">95</td><td class="hits">5</td><td class="source">  var pre_prefix = 'PRE_',</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">      post_prefix = 'POST_';</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">  // Register a pre listener</td></tr><tr class="hit"><td class="line">99</td><td class="hits">5</td><td class="source">  this.pre = function(event, listener, fn) {</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">101</td><td class="hits">2</td><td class="source">    self.emitter.on(pre_prefix + event, fn);</td></tr><tr class="hit"><td class="line">102</td><td class="hits">2</td><td class="source">    this.events[event].preListeners[listener] = this.events[event].preListeners[listener] || [];</td></tr><tr class="hit"><td class="line">103</td><td class="hits">2</td><td class="source">    this.events[event].preListeners[listener].push({</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">      name: fn.name</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">106</td><td class="hits">2</td><td class="source">    this.events[event].preListeners['#'] += 1;</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">108</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">  // Register a post listener</td></tr><tr class="hit"><td class="line">110</td><td class="hits">5</td><td class="source">  this.post = function(event, listener, fn) {</td></tr><tr class="hit"><td class="line">111</td><td class="hits">2</td><td class="source">    self.emitter.on(post_prefix + event, fn);</td></tr><tr class="hit"><td class="line">112</td><td class="hits">2</td><td class="source">    this.events[event].postListeners[listener] = this.events[event].postListeners[listener] || [];</td></tr><tr class="hit"><td class="line">113</td><td class="hits">2</td><td class="source">    this.events[event].postListeners[listener].push({</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">      name: fn.name</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">116</td><td class="hits">2</td><td class="source">    this.events[event].postListeners['#'] += 1;</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">  // Register a custom event listener</td></tr><tr class="hit"><td class="line">120</td><td class="hits">5</td><td class="source">  this.custom = function(event, key, listener, fn) {</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">122</td><td class="hits">2</td><td class="source">    self.emitter.on(event + '_' + key, fn);</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">    // Register under key</td></tr><tr class="hit"><td class="line">125</td><td class="hits">2</td><td class="source">    this.events[event].custom[key] = this.events[event].custom[key] || {</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source">      customListeners: {</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">        '#': 0</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">    // Register</td></tr><tr class="hit"><td class="line">132</td><td class="hits">2</td><td class="source">    this.events[event].custom[key].customListeners[listener] = this.events[event].custom[key].customListeners[listener] || [];</td></tr><tr class="hit"><td class="line">133</td><td class="hits">2</td><td class="source">    this.events[event].custom[key].customListeners[listener].push({</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">      name: fn.name</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">136</td><td class="hits">2</td><td class="source">    this.events[event].custom[key].customListeners['#'] += 1;</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">  // Emit a pre event</td></tr><tr class="hit"><td class="line">141</td><td class="hits">5</td><td class="source">  this.pre_emit = function(event, data, next) {</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">143</td><td class="hits">2</td><td class="source">    var cb;</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">    // Create a callback to track completion of all events (only if next exists)</td></tr><tr class="hit"><td class="line">146</td><td class="hits">2</td><td class="source">    if (typeof next === &quot;function&quot;) {</td></tr><tr class="hit"><td class="line">147</td><td class="hits">1</td><td class="source">      cb = createCallback(this.events[event].preListeners['#'], data, next);</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">149</td><td class="hits">1</td><td class="source">      cb = function() {};</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">152</td><td class="hits">2</td><td class="source">    if (this.events[event] &amp;&amp; this.events[event].enabled) {</td></tr><tr class="hit"><td class="line">153</td><td class="hits">2</td><td class="source">      self.emitter.emit(pre_prefix + event, pre_prefix + event, data, cb);</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source">  // Emit a post event</td></tr><tr class="hit"><td class="line">159</td><td class="hits">5</td><td class="source">  this.post_emit = function(event, data, next) {</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">161</td><td class="hits">2</td><td class="source">    var cb;</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    // Create a callback to track completion of all events (only if next exists)</td></tr><tr class="hit"><td class="line">164</td><td class="hits">2</td><td class="source">    if (typeof next === &quot;function&quot;) {</td></tr><tr class="hit"><td class="line">165</td><td class="hits">1</td><td class="source">      cb = createCallback(this.events[event].postListeners['#'], data, next);</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">167</td><td class="hits">1</td><td class="source">      cb = function() {};</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">170</td><td class="hits">2</td><td class="source">    if (this.events[event] &amp;&amp; this.events[event].enabled) {</td></tr><tr class="hit"><td class="line">171</td><td class="hits">2</td><td class="source">      self.emitter.emit(post_prefix + event, post_prefix + event, data, cb);</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source">  // Emit a custom event</td></tr><tr class="hit"><td class="line">177</td><td class="hits">5</td><td class="source">  this.custom_emit = function(event, key, data, next) {</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">179</td><td class="hits">2</td><td class="source">    var cb;</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">181</td><td class="hits">2</td><td class="source">    if (this.events[event] &amp;&amp; this.events[event].custom[key] &amp;&amp; this.events[event].enabled) {</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">      // Create a callback to track completion of all events (only if next exists)</td></tr><tr class="hit"><td class="line">184</td><td class="hits">2</td><td class="source">      if (typeof next === &quot;function&quot;) {</td></tr><tr class="hit"><td class="line">185</td><td class="hits">2</td><td class="source">        cb = createCallback(this.events[event].custom[key].customListeners['#'], data, next);</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">187</td><td class="hits">0</td><td class="source">        cb = function() {};</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">190</td><td class="hits">2</td><td class="source">      self.emitter.emit(event + '_' + key, event + '_' + key, data, cb);</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">193</td><td class="hits">0</td><td class="source">      next(data);</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">  // Create a curried callback function for use in the emit code</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">200</td><td class="hits">5</td><td class="source">  function createCallback(total, data, callback) {</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">202</td><td class="hits">4</td><td class="source">    var count = 0,</td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">        total = total,</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source">        outputStack = [];</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">206</td><td class="hits">8</td><td class="source">    if (data) outputStack.push(data);</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">    // No listeners, so callback immediately</td></tr><tr class="hit"><td class="line">209</td><td class="hits">4</td><td class="source">    if (total === 0) {</td></tr><tr class="miss"><td class="line">210</td><td class="hits">0</td><td class="source">      callback(data);</td></tr><tr class="miss"><td class="line">211</td><td class="hits">0</td><td class="source">      return;</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">214</td><td class="hits">4</td><td class="source">    return function(data) {</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">216</td><td class="hits">4</td><td class="source">      count += 1;</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">218</td><td class="hits">8</td><td class="source">      if (data) outputStack.push(data);</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source">      // Merge the outputs from the stack</td></tr><tr class="hit"><td class="line">221</td><td class="hits">4</td><td class="source">      if (count === total) {</td></tr><tr class="hit"><td class="line">222</td><td class="hits">4</td><td class="source">        callback(mergeArray(outputStack));</td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">232</td><td class="hits"></td><td class="source"> * Module event emitter, object that enables modules to emit events.</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source"> * This contains both server and request scope event emitters, though clearly</td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source"> * an instance of an object only emits one or the other depending on</td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source"> * where it is instantiated.</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">238</td><td class="hits">1</td><td class="source">function ModuleInitEventEmitter(moduleName, options) {</td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">240</td><td class="hits">9</td><td class="source">  events.EventEmitter.call(this);</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">242</td><td class="hits">9</td><td class="source">  var self = this;</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">244</td><td class="hits">9</td><td class="source">  self.options = options || {};</td></tr><tr class="hit"><td class="line">245</td><td class="hits">9</td><td class="source">  this.moduleName = moduleName;</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">247</td><td class="hits"></td><td class="source">  // Set the max listeners</td></tr><tr class="hit"><td class="line">248</td><td class="hits">9</td><td class="source">  var maxListeners = self.options.maxListeners || 100;</td></tr><tr class="hit"><td class="line">249</td><td class="hits">9</td><td class="source">  this.setMaxListeners(maxListeners);</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">251</td><td class="hits">9</td><td class="source">  this.init_start = function(options) {</td></tr><tr class="hit"><td class="line">252</td><td class="hits">8</td><td class="source">    self.emit(exports.INIT_START, self.moduleName, options);</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">255</td><td class="hits">9</td><td class="source">  this.init_finish = function(options) {</td></tr><tr class="hit"><td class="line">256</td><td class="hits">8</td><td class="source">    self.emit(exports.INIT_FINISH, self.moduleName, options);</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source"> * Event listener linked to the module itself</td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source"> * This is for server events (e.g. init, reload)</td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source"> * No events here can sit within the request context as</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source"> * they will apply to all requests</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">269</td><td class="hits">1</td><td class="source">function addModuleEventListener(module, options) {</td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">271</td><td class="hits">9</td><td class="source">  options = options || {};</td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">273</td><td class="hits">9</td><td class="source">  var moduleEventEmitter = module.event = new ModuleInitEventEmitter(module.name, options),</td></tr><tr><td class="line">274</td><td class="hits"></td><td class="source">      notifyDependencyFn = options.notifyDependencyFn || function() {};</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">  // Link events</td></tr><tr class="hit"><td class="line">277</td><td class="hits">9</td><td class="source">  moduleEventEmitter.once(exports.INIT_START, function(moduleName, options) {</td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source">    // Do nothing</td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">280</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">281</td><td class="hits">9</td><td class="source">  moduleEventEmitter.once(exports.INIT_FINISH, function(moduleName, options) {</td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source">    // Check for dependent modules, init them</td></tr><tr class="hit"><td class="line">283</td><td class="hits">8</td><td class="source">    notifyDependencyFn(moduleName, options);</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">288</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">289</td><td class="hits"></td><td class="source"> * Module event emitter, object that enables modules to emit events.</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source"> * This contains both server and request scope event emitters, though clearly</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source"> * an instance of an object only emits one or the other depending on</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> * where it is instantiated.</td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">294</td><td class="hits">1</td><td class="source">function ModuleRequestEventEmitter(moduleName, options) {</td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">296</td><td class="hits">17</td><td class="source">  events.EventEmitter.call(this);</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source">  // Refresh the require</td></tr><tr class="hit"><td class="line">299</td><td class="hits">17</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">300</td><td class="hits">17</td><td class="source">  self.options = options || {};</td></tr><tr class="hit"><td class="line">301</td><td class="hits">17</td><td class="source">  self.moduleName = moduleName;</td></tr><tr><td class="line">302</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source">  // Set the max listeners</td></tr><tr class="hit"><td class="line">304</td><td class="hits">17</td><td class="source">  var maxListeners = self.options.maxListeners || 100;</td></tr><tr class="hit"><td class="line">305</td><td class="hits">17</td><td class="source">  this.setMaxListeners(maxListeners);</td></tr><tr><td class="line">306</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">307</td><td class="hits">17</td><td class="source">  this.route_start = function(options) {</td></tr><tr class="hit"><td class="line">308</td><td class="hits">9</td><td class="source">    self.emit(exports.ROUTE_START, self.moduleName, options);</td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">311</td><td class="hits">17</td><td class="source">  this.route_finish = function(options) {</td></tr><tr class="hit"><td class="line">312</td><td class="hits">9</td><td class="source">    self.emit(exports.ROUTE_FINISH, self.moduleName, options);</td></tr><tr><td class="line">313</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">315</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">317</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">318</td><td class="hits"></td><td class="source"> * Event listener linked to the request object</td></tr><tr><td class="line">319</td><td class="hits"></td><td class="source"> * This is the object that will listen to each module event emitter</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source"> * and call other modules or perform other defined functions</td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">322</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">323</td><td class="hits">1</td><td class="source">function RequestEventListener(options) {</td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">325</td><td class="hits">5</td><td class="source">  options = options || {};</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source">  // Register a module, listen to its events</td></tr><tr class="hit"><td class="line">328</td><td class="hits">5</td><td class="source">  var self = this,</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source">      notifyDependencyFn = options.notifyDependencyFn || function() {},</td></tr><tr><td class="line">330</td><td class="hits"></td><td class="source">      registerDependenciesFn = options.registerDependenciesFn || function() {};</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">332</td><td class="hits"></td><td class="source">  // Local hash of module event emitters, used to track routing status</td></tr><tr class="hit"><td class="line">333</td><td class="hits">5</td><td class="source">  this.modules = {};</td></tr><tr><td class="line">334</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">335</td><td class="hits"></td><td class="source">  // Register a module</td></tr><tr class="hit"><td class="line">336</td><td class="hits">5</td><td class="source">  this.registerModule = function(req, res, moduleName, options) {</td></tr><tr><td class="line">337</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">338</td><td class="hits"></td><td class="source">    // Register event emitter</td></tr><tr class="hit"><td class="line">339</td><td class="hits">17</td><td class="source">    var moduleEventEmitter = self.modules[moduleName] = new ModuleRequestEventEmitter(moduleName, options);</td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">341</td><td class="hits"></td><td class="source">    // Configure event listener</td></tr><tr class="hit"><td class="line">342</td><td class="hits">17</td><td class="source">    self.modules[moduleName].routed = false; // Is it done</td></tr><tr class="hit"><td class="line">343</td><td class="hits">17</td><td class="source">    self.modules[moduleName].check = {}; // Hash of dependent modules to check if initialised</td></tr><tr><td class="line">344</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">345</td><td class="hits"></td><td class="source">    // Curried function to notify dependent modules that we have finished</td></tr><tr class="hit"><td class="line">346</td><td class="hits">17</td><td class="source">    var notifyDependencies = function(moduleName) {</td></tr><tr class="hit"><td class="line">347</td><td class="hits">9</td><td class="source">        notifyDependencyFn(req, res, moduleName, self.modules);</td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">350</td><td class="hits">17</td><td class="source">    registerDependenciesFn(self, moduleName);</td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source">    </td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source">    // Start</td></tr><tr class="hit"><td class="line">353</td><td class="hits">17</td><td class="source">    moduleEventEmitter.once(exports.ROUTE_START, function(moduleName, options) {</td></tr><tr class="hit"><td class="line">354</td><td class="hits">9</td><td class="source">      self.modules[moduleName].start = new Date();</td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">357</td><td class="hits"></td><td class="source">    // Finish</td></tr><tr class="hit"><td class="line">358</td><td class="hits">17</td><td class="source">    moduleEventEmitter.once(exports.ROUTE_FINISH, function(moduleName, options) {</td></tr><tr><td class="line">359</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">360</td><td class="hits">9</td><td class="source">      self.modules[moduleName].finish = new Date();</td></tr><tr class="hit"><td class="line">361</td><td class="hits">9</td><td class="source">      self.modules[moduleName].duration = self.modules[moduleName].finish - self.modules[moduleName].start;</td></tr><tr class="hit"><td class="line">362</td><td class="hits">9</td><td class="source">      self.modules[moduleName].routed = true;</td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">364</td><td class="hits"></td><td class="source">      // Callback to Calipso to notify dependent objects of route</td></tr><tr><td class="line">365</td><td class="hits"></td><td class="source">      // calipso.notifyDependenciesOfRoute(req, res, moduleName, self.modules);</td></tr><tr class="hit"><td class="line">366</td><td class="hits">9</td><td class="source">      notifyDependencies(moduleName);</td></tr><tr><td class="line">367</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">368</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">369</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">371</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">372</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">373</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">374</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">375</td><td class="hits"></td><td class="source"> * Inherits</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">377</td><td class="hits">1</td><td class="source">util.inherits(ModuleInitEventEmitter, events.EventEmitter);</td></tr><tr class="hit"><td class="line">378</td><td class="hits">1</td><td class="source">util.inherits(ModuleRequestEventEmitter, events.EventEmitter);</td></tr><tr><td class="line">379</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">381</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">382</td><td class="hits"></td><td class="source"> *  Helper functions TODO CONSOLIDATE!</td></tr><tr><td class="line">383</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">384</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">385</td><td class="hits">1</td><td class="source">function mergeArray(arr, first) {</td></tr><tr class="hit"><td class="line">386</td><td class="hits">4</td><td class="source">  var output = {};</td></tr><tr class="hit"><td class="line">387</td><td class="hits">4</td><td class="source">  arr.forEach(function(value, key) {</td></tr><tr class="hit"><td class="line">388</td><td class="hits">8</td><td class="source">    if (first) {</td></tr><tr class="miss"><td class="line">389</td><td class="hits">0</td><td class="source">      output = merge(value, output);</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">391</td><td class="hits">8</td><td class="source">      output = merge(output, value);</td></tr><tr><td class="line">392</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">393</td><td class="hits"></td><td class="source">  });</td></tr><tr class="hit"><td class="line">394</td><td class="hits">4</td><td class="source">  return output;</td></tr><tr><td class="line">395</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">396</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">397</td><td class="hits">1</td><td class="source">function merge(a, b) {</td></tr><tr class="hit"><td class="line">398</td><td class="hits">8</td><td class="source">  if (a &amp;&amp; b) {</td></tr><tr class="hit"><td class="line">399</td><td class="hits">8</td><td class="source">    for (var key in b) {</td></tr><tr class="hit"><td class="line">400</td><td class="hits">16</td><td class="source">      a[key] = b[key];</td></tr><tr><td class="line">401</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">402</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">403</td><td class="hits">8</td><td class="source">  return a;</td></tr><tr><td class="line">404</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Form.js">core/Form.js</h2><div id="stats" class="terrible"><div class="percentage">13%</div><div class="sloc">301</div><div class="hits">40</div><div class="misses">261</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!a</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Form Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * Core form generation module.</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * This is loaded by calipso as a plugin, so can be replaced by modules.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * Module must expose a single object as below, with a single</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> * function that is called by other modules to generate form markup.</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> * This is most likely a synchronous call, but has been written asynch just</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> * in case a module author wants to make an asynch version (for some reason!).</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * TODO: validation, redisplay of submitted values</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">21</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">  qs = require('qs'),</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">  merge = require('connect').utils.merge;</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">// Global variable (in this context) for translation function</td></tr><tr class="hit"><td class="line">28</td><td class="hits">1</td><td class="source">var t;</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> * The default calipso form object, with default configuration values.</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> * Constructor</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">34</td><td class="hits">1</td><td class="source">function Form() {</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  // TODO - tagStyle should also affect whether attributes can be minimised ('selected' vs. 'selected=&quot;selected&quot;')</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">  // tagStyle should be one of [html, xhtml, xml]</td></tr><tr class="hit"><td class="line">39</td><td class="hits">1</td><td class="source">  this.tagStyle = &quot;html&quot;;</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">  // adjust the way tags are closed based on the given tagStyle.</td></tr><tr class="hit"><td class="line">42</td><td class="hits">1</td><td class="source">  this.tagClose = this.tagStyle == &quot;html&quot; ? '&gt;' : ' /&gt;';</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">  // cheap way of ensuring unique radio ids</td></tr><tr class="hit"><td class="line">45</td><td class="hits">1</td><td class="source">  this.radioCount = 0;</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">49</td><td class="hits">1</td><td class="source">var f = new Form();</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">51</td><td class="hits">1</td><td class="source">var me = Form.prototype;</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">// instead of referring to the singleton (`f`), we could implement a function</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">// that would give us the current instance, for a more sure `this`</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">// but it would be a little bit slower, due to the function call</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">//me.getInstance = function(){</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">//  return this;</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">//};</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">//me.getContext = function(){</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">//  return this;</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">//};</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">/* just an idea.</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">function getAttributeString(el){</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">  var validAttrs = ['type','name','id','class','value','disabled'];</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">  var output = '';</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source">  validAttrs.forEach(function(i, attrName){</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">    if(el[attrName]){</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">      output += ' ' + attrName + '=&quot;' + el.attr[attrName] + '&quot;';</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">  return output;</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">*/</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">// if complete for every country, this will be a lot of data and should</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">// probably be broken out to a separate file.</td></tr><tr class="hit"><td class="line">78</td><td class="hits">1</td><td class="source">me.countries = [</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">  &quot;Afghanistan&quot;, &quot;Albania&quot;, &quot;Algeria&quot;, &quot;Andorra&quot;, &quot;Angola&quot;,</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">  &quot;Antigua and Barbuda&quot;, &quot;Argentina&quot;, &quot;Armenia&quot;, &quot;Australia&quot;, &quot;Austria&quot;,</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">  &quot;Azerbaijan&quot;, &quot;Bahamas&quot;, &quot;Bahrain&quot;, &quot;Bangladesh&quot;, &quot;Barbados&quot;, &quot;Belarus&quot;,</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">  &quot;Belgium&quot;, &quot;Belize&quot;, &quot;Benin&quot;, &quot;Bhutan&quot;, &quot;Bolivia&quot;, &quot;Bosnia and Herzegovina&quot;,</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">  &quot;Botswana&quot;, &quot;Brazil&quot;, &quot;Brunei&quot;, &quot;Bulgaria&quot;, &quot;Burkina Faso&quot;, &quot;Burundi&quot;,</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">  &quot;Cambodia&quot;, &quot;Cameroon&quot;, &quot;Canada&quot;, &quot;Cape Verde&quot;, &quot;Central African Republic&quot;,</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source">  &quot;Chad&quot;, &quot;Chile&quot;, &quot;China (People's Republic of China)&quot;, &quot;Colombia&quot;, &quot;Comoros&quot;,</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">  &quot;Democratic Republic of the Congo&quot;, &quot;Republic of the Congo&quot;,</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">  &quot;Costa Rica&quot;, &quot;C&amp;#195;&amp;#180;te d'Ivoire&quot;, &quot;Croatia&quot;, &quot;Cuba&quot;, &quot;Cyprus&quot;,</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">  &quot;Czech Republic&quot;, &quot;Denmark, the Kingdom of&quot;, &quot;Djibouti&quot;, &quot;Dominica&quot;,</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">  &quot;Dominican Republic&quot;, &quot;East Timor&quot;, &quot;Ecuador&quot;, &quot;Egypt&quot;, &quot;El Salvador&quot;,</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">  &quot;Equatorial Guinea&quot;, &quot;Eritrea&quot;, &quot;Estonia&quot;, &quot;Ethiopia&quot;, &quot;Fiji&quot;,</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">  &quot;Finland&quot;, &quot;France&quot;, &quot;Gabon&quot;, &quot;Gambia&quot;, &quot;Georgia&quot;, &quot;Germany&quot;, &quot;Ghana&quot;,</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">  &quot;Greece&quot;, &quot;Grenada&quot;, &quot;Guatemala&quot;, &quot;Guinea&quot;, &quot;Guinea-Bissau&quot;, &quot;Guyana&quot;,</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">  &quot;Haiti&quot;, &quot;Honduras&quot;, &quot;Hungary&quot;, &quot;Iceland&quot;, &quot;India&quot;, &quot;Indonesia&quot;, &quot;Iran&quot;,</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">  &quot;Iraq&quot;, &quot;Ireland&quot;, &quot;Israel&quot;, &quot;Italy&quot;, &quot;Jamaica&quot;, &quot;Japan&quot;, &quot;Jordan&quot;,</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source">  &quot;Kazakhstan&quot;, &quot;Kenya&quot;, &quot;Kiribati&quot;, &quot;North Korea&quot;, &quot;South Korea&quot;,</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">  &quot;Kosovo&quot;, &quot;Kuwait&quot;, &quot;Kyrgyzstan&quot;, &quot;Laos&quot;, &quot;Latvia&quot;, &quot;Lebanon&quot;,</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">  &quot;Lesotho&quot;, &quot;Liberia&quot;, &quot;Libya&quot;, &quot;Liechtenstein&quot;, &quot;Lithuania&quot;, &quot;Luxembourg&quot;,</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">  &quot;Macedonia&quot;, &quot;Madagascar&quot;, &quot;Malawi&quot;, &quot;Malaysia&quot;, &quot;Maldives&quot;, &quot;Mali&quot;,</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source">  &quot;Malta&quot;, &quot;Marshall Islands&quot;, &quot;Mauritania&quot;, &quot;Mauritius&quot;, &quot;Mexico&quot;,</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">  &quot;Federated States of Micronesia&quot;, &quot;Moldova&quot;, &quot;Monaco&quot;, &quot;Mongolia&quot;,</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">  &quot;Montenegro&quot;, &quot;Morocco&quot;, &quot;Mozambique&quot;, &quot;Myanmar&quot;, &quot;Namibia&quot;, &quot;Nauru&quot;,</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source">  &quot;Nepal&quot;, &quot;Netherlands, the Kingdom of&quot;, &quot;New Zealand&quot;, &quot;Nicaragua&quot;, &quot;Niger&quot;,</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">  &quot;Nigeria&quot;, &quot;Norway&quot;, &quot;Oman&quot;, &quot;Pakistan&quot;, &quot;Palau&quot;, &quot;Palestinian territories&quot;,</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">  &quot;Panama&quot;, &quot;Papua New Guinea&quot;, &quot;Paraguay&quot;, &quot;Peru&quot;, &quot;Philippines&quot;, &quot;Poland&quot;,</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source">  &quot;Portugal&quot;, &quot;Qatar&quot;, &quot;Romania&quot;, &quot;Russia&quot;, &quot;Rwanda&quot;, &quot;Saint Kitts and Nevis&quot;,</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">  &quot;Saint Lucia&quot;, &quot;Saint Vincent and the Grenadines&quot;, &quot;Samoa&quot;, &quot;San Marino&quot;,</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">  &quot;S&amp;#195;&amp;#163;o Tom&amp;#195;&amp;#169; and Pr&amp;#195;&amp;#173;ncipe&quot;, &quot;Saudi Arabia&quot;, &quot;Senegal&quot;, &quot;Serbia&quot;, &quot;Seychelles&quot;,</td></tr><tr><td class="line">108</td><td class="hits"></td><td class="source">  &quot;Sierra Leone&quot;, &quot;Singapore&quot;, &quot;Slovakia&quot;, &quot;Slovenia&quot;, &quot;Solomon Islands&quot;,</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">  &quot;Somalia&quot;, &quot;South Africa&quot;, &quot;South Sudan&quot;, &quot;Spain&quot;, &quot;Sri Lanka&quot;, &quot;Sudan&quot;,</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">  &quot;Suriname&quot;, &quot;Swaziland&quot;, &quot;Sweden&quot;, &quot;Switzerland&quot;, &quot;Syria&quot;,</td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">  &quot;Taiwan (Republic of China)&quot;, &quot;Tajikistan&quot;, &quot;Tanzania&quot;, &quot;Thailand&quot;, &quot;Togo&quot;,</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">  &quot;Tonga&quot;, &quot;Trinidad and Tobago&quot;, &quot;Tunisia&quot;, &quot;Turkey&quot;, &quot;Turkmenistan&quot;,</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">  &quot;Tuvalu&quot;, &quot;Uganda&quot;, &quot;Ukraine&quot;, &quot;United Arab Emirates&quot;, &quot;United Kingdom&quot;,</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">  &quot;United States&quot;, &quot;Uruguay&quot;, &quot;Uzbekistan&quot;, &quot;Vanuatu&quot;, &quot;Vatican City&quot;,</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source">  &quot;Venezuela&quot;, &quot;Vietnam&quot;, &quot;Western Sahara&quot;, &quot;Yemen&quot;, &quot;Zambia&quot;, &quot;Zimbabwe&quot;</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">];</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">118</td><td class="hits">1</td><td class="source">me.states = {</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">  &quot;United States&quot;: {</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">    AL:&quot;Alabama&quot;,</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">    AK:&quot;Alaska&quot;,</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">    AZ:&quot;Arizona&quot;,</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">    AR:&quot;Arkansas&quot;,</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">    CA:&quot;California&quot;,</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">    CO:&quot;Colorado&quot;,</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source">    CT:&quot;Connecticut&quot;,</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">    DE:&quot;Delaware&quot;,</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">    DC:&quot;District Of Columbia&quot;,</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">    FL:&quot;Florida&quot;,</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">    GA:&quot;Georgia&quot;,</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">    HI:&quot;Hawaii&quot;,</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">    ID:&quot;Idaho&quot;,</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">    IL:&quot;Illinois&quot;,</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">    IN:&quot;Indiana&quot;,</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">    IA:&quot;Iowa&quot;,</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">    KS:&quot;Kansas&quot;,</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">    KY:&quot;Kentucky&quot;,</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">    LA:&quot;Louisiana&quot;,</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">    ME:&quot;Maine&quot;,</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">    MD:&quot;Maryland&quot;,</td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">    MA:&quot;Massachusetts&quot;,</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source">    MI:&quot;Michigan&quot;,</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">    MN:&quot;Minnesota&quot;,</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source">    MS:&quot;Mississippi&quot;,</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">    MO:&quot;Missouri&quot;,</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">    MT:&quot;Montana&quot;,</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">    NE:&quot;Nebraska&quot;,</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">    NV:&quot;Nevada&quot;,</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source">    NH:&quot;New Hampshire&quot;,</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">    NJ:&quot;New Jersey&quot;,</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source">    NM:&quot;New Mexico&quot;,</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source">    NY:&quot;New York&quot;,</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source">    NC:&quot;North Carolina&quot;,</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">    ND:&quot;North Dakota&quot;,</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">    OH:&quot;Ohio&quot;,</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">    OK:&quot;Oklahoma&quot;,</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">    OR:&quot;Oregon&quot;,</td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source">    PA:&quot;Pennsylvania&quot;,</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source">    RI:&quot;Rhode Island&quot;,</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source">    SC:&quot;South Carolina&quot;,</td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source">    SD:&quot;South Dakota&quot;,</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source">    TN:&quot;Tennessee&quot;,</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    TX:&quot;Texas&quot;,</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source">    UT:&quot;Utah&quot;,</td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source">    VT:&quot;Vermont&quot;,</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">    VA:&quot;Virginia&quot;,</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">    WA:&quot;Washington&quot;,</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">    WV:&quot;West Virginia&quot;,</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">    WI:&quot;Wisconsin&quot;,</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source">    WY:&quot;Wyoming&quot;</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source"> * Functions for each tag type, these are now exposed directly on the object</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source"> * so that they can be redefined within modules (e.g. in a module that provides</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> * a rich text editor), or a module can add new types specific to that module.</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source"> * Current field types available are:</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> *      text : default text field (used if no function matches field type)</td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source"> *      textarea : default textarea, can set rows in form definition to control rows in a textarea field item.</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source"> *      hidden : hidden field</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source"> *      select : single select box, requires values to be set (as array or function)</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source"> *      submit : submit button</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> *      button : general button</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source"> *      date : date input control (very rudimentary)</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source"> *      time : time input controls</td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source"> *      datetime : combination of date and time controls</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> *      crontime : crontime editor (6 small text boxes)</td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source"> *      password : password field</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source"> *      checkbox : checkbox field</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source"> *      radio : radio button</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source"> *      file : file field</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">**/</td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">199</td><td class="hits">1</td><td class="source">me.defaultTagRenderer = function(field, value, bare){</td></tr><tr class="miss"><td class="line">200</td><td class="hits">0</td><td class="source">  var isCheckable = field.type == 'radio' || field.type == 'checkbox';</td></tr><tr class="miss"><td class="line">201</td><td class="hits">0</td><td class="source">  var checked = field.checked || (isCheckable &amp;&amp; value &amp;&amp; (field.value == value || value===true));</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">  //console.log('... field: ', field, value);</td></tr><tr class="miss"><td class="line">204</td><td class="hits">0</td><td class="source">  var tagOutput = &quot;&quot;;</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">206</td><td class="hits">0</td><td class="source">  if(field.type == 'checkbox' &amp;&amp; !field.readonly &amp;&amp; !field.disabled){</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">    // Workaround for readonly/disabled fields (esp. checkboxes/radios) - add a hidden field with the value</td></tr><tr class="miss"><td class="line">208</td><td class="hits">0</td><td class="source">    tagOutput += '&lt;input type=&quot;hidden&quot; name=&quot;' + field.name + '&quot; value=&quot;false&quot; /&gt;';</td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">211</td><td class="hits">0</td><td class="source">  tagOutput += '&lt;input type=&quot;' + field.type + '&quot;'</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">  + ' class=&quot;'+ field.type + (field.cls ? ' ' + field.cls : &quot;&quot;) + (field.labelFirst ? ' labelFirst' : '') + '&quot;'</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source">  + ' name=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">  + (field.href ? ' onClick=\'window.location=&quot;' + field.href + '&quot;\';' : '')</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">  + ' id=&quot;' + (field.id ? field.id : field.name + (field.type=='radio' ? (++f.radioCount) : '')) + '&quot;'</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">  + (field.src ? ' src=&quot;' + field.src + '&quot;' : '') // for input type=image .. which should be avoided anyway.</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source">  + (field.multiple ? ' multiple=&quot;' + field.multiple + '&quot;' : '') // for input type=file</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">  + ' value=&quot;' + (value || field.value || (isCheckable &amp;&amp; 'on') || '') + '&quot;'</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">  + (field.readonly || field.disabled ? ' disabled' : '')</td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source">  + (checked ? ' checked' : '')</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source">  + f.tagClose;</td></tr><tr class="miss"><td class="line">222</td><td class="hits">0</td><td class="source">  if(field.readonly || field.disabled){</td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source">    // Workaround for readonly/disabled fields (esp. checkboxes/radios) - add a hidden field with the value</td></tr><tr class="miss"><td class="line">224</td><td class="hits">0</td><td class="source">    tagOutput += '&lt;input type=&quot;hidden&quot; name=&quot;' + field.name + '&quot; value=&quot;' + (checked ? 'true' : 'false') + '&quot; /&gt;';</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">227</td><td class="hits">0</td><td class="source">  return bare ? tagOutput : me.decorateField(field, tagOutput);</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">231</td><td class="hits">1</td><td class="source">me.decorateField = function(field, tagHTML){</td></tr><tr class="miss"><td class="line">232</td><td class="hits">0</td><td class="source">  calipso.silly('FORM: decorateField, field: ', field);</td></tr><tr class="miss"><td class="line">233</td><td class="hits">0</td><td class="source">  var isCheckable = !field.labelFirst &amp;&amp; (field.type == &quot;checkbox&quot; || field.type == &quot;radio&quot;);</td></tr><tr class="miss"><td class="line">234</td><td class="hits">0</td><td class="source">  var labelHTML = field.label ? (</td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source">    '&lt;label' + (isCheckable ? ' class=&quot;for-checkable&quot;' : '')</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source">    + ' for=&quot;' + field.name + (field.type == 'radio' ? f.radioCount : '')</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">    + '&quot;&gt;' + t(field.label) + (isCheckable ? '' : ':') + '&lt;/label&gt;'</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source">  ) : '';</td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">240</td><td class="hits">0</td><td class="source">  var wrapperId = (</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source">    field.name.replace(/\[/g, '_').replace(/\]/g, '')</td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source">    + (field.type == 'radio' ? '-radio' + me.radioCount : '')</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source">  );</td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">245</td><td class="hits">0</td><td class="source">  return field.label &amp;&amp; field.label.length &gt; 0 ? (</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source">    '&lt;div class=&quot;form-item field-type-' + field.type + '&quot; id=&quot;' + wrapperId + '-wrapper&quot;&gt;' +</td></tr><tr><td class="line">247</td><td class="hits"></td><td class="source">    '&lt;div class=&quot;form-field&quot;&gt;' +</td></tr><tr><td class="line">248</td><td class="hits"></td><td class="source">      // put checkboxes and radios (&quot;checkables&quot;) before their labels, unless field.labelFirst is true</td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">      (isCheckable ? tagHTML + labelHTML : labelHTML + tagHTML) +</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source">    '&lt;/div&gt;' +</td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source">    (field.description ? '&lt;span class=&quot;description ' + field.type + '-description&quot;&gt;' + t(field.description) + '&lt;/span&gt;' : '') +</td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">    '&lt;/div&gt;'</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">  ) : tagHTML;</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">255</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source">// if there is no `canContain` or `cannotContain`, then the element is not a container.</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">// the following psuedofunction should suffice:</td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source">// x.canContain(y) =</td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source">//   ((x.canContain &amp;&amp; y in x.canContain) || (x.cannotContain &amp;&amp; !(y in x.cannotContain)))</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">//   &amp;&amp; (!y.canBeContainedBy || x in y.canBeContainedBy)</td></tr><tr class="hit"><td class="line">261</td><td class="hits">1</td><td class="source">me.elementTypes = {</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">  'page': {</td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source">    cannotContain: ['page'],</td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source">    render: function(el){}</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source">  'section': {</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source">    cannotContain: ['page'],</td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source">    isTab : false,</td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source">    render: function(el, values, isTabs){</td></tr><tr class="miss"><td class="line">272</td><td class="hits">0</td><td class="source">      return (</td></tr><tr><td class="line">273</td><td class="hits"></td><td class="source">        '&lt;section' + (el.isTab || isTabs ? ' class=&quot;tab-content&quot;':'') + ' id=&quot;' + el.id + '&quot;&gt;' +</td></tr><tr><td class="line">274</td><td class="hits"></td><td class="source">          (el.label ? '&lt;h3&gt;' + t(el.label) + '&lt;/h3&gt;' : '') +</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source">          (el.description ? '&lt;p&gt;' + el.description + '&lt;/p&gt;' : '') +</td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">          '&lt;div class=&quot;section-fields&quot;&gt;' +</td></tr><tr><td class="line">277</td><td class="hits"></td><td class="source">            me.render_fields(el, values) +</td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source">          '&lt;/div&gt;' +</td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source">        '&lt;/section&gt;'</td></tr><tr><td class="line">280</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">281</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">  // todo: allow for pre-rendered markup for the description, or other renderers (such as markdown)</td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source">  'fieldset': {</td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source">    cannotContain: ['section', 'page'],</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source">    render: function(el, values){</td></tr><tr class="miss"><td class="line">288</td><td class="hits">0</td><td class="source">      if(!el.label) el.label = el.legend;</td></tr><tr class="miss"><td class="line">289</td><td class="hits">0</td><td class="source">      return (</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source">        '&lt;fieldset class=&quot;' + (el.type != 'fieldset' ? el.type + '-fieldset' : 'fieldset') + '&quot;&gt;' +</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source">          // &lt;legend&gt; is preferable, but legends are not fully stylable, so 'label' = &lt;h4&gt;</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source">          (el.label ? '&lt;h4&gt;' + t(el.label) + '&lt;/h4&gt;' : '') +</td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source">          (el.description ? '&lt;p&gt;' + el.description + '&lt;/p&gt;' : '') +</td></tr><tr><td class="line">294</td><td class="hits"></td><td class="source">          '&lt;div class=&quot;fieldset-fields&quot;&gt;' +</td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source">            me.render_fields(el, values) +</td></tr><tr><td class="line">296</td><td class="hits"></td><td class="source">          '&lt;/div&gt;' +</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source">        '&lt;/fieldset&gt;'</td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">299</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">300</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">302</td><td class="hits"></td><td class="source">  // special .. might also be used as a container (i.e., depending on what radio is active, elements 'under' it are active?)</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source">  // special - have to share ids .. are part of a set - TODO - allow for more than one radio group (already done?)</td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source">  'radios': { // it's a container because radios must belong to a 'set' .. also, sometimes a form uses radios kindof like tabs....</td></tr><tr><td class="line">305</td><td class="hits"></td><td class="source">    canContain: ['option'],</td></tr><tr><td class="line">306</td><td class="hits"></td><td class="source">    render: function(field, values){</td></tr><tr class="miss"><td class="line">307</td><td class="hits">0</td><td class="source">      return me.elementTypes.fieldset.render(field, values);</td></tr><tr><td class="line">308</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">311</td><td class="hits"></td><td class="source">  // special .. might also be used as a container (i.e., depending on whether a checkbox is checked, elements 'under' it are active?)</td></tr><tr><td class="line">312</td><td class="hits"></td><td class="source">  'checkboxes': {</td></tr><tr><td class="line">313</td><td class="hits"></td><td class="source">    canContain: ['option'],</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">    render: function(field, values){</td></tr><tr class="miss"><td class="line">315</td><td class="hits">0</td><td class="source">      return me.elementTypes.fieldset.render(field, values);</td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">317</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">318</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">319</td><td class="hits"></td><td class="source">  'select': { // it's a container because it contains options</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source">    canContain: ['options','optgroup'],</td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source">    render: function(field, value){</td></tr><tr><td class="line">322</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">323</td><td class="hits">0</td><td class="source">      var tagOutput =  '&lt;select'</td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source">      + ' class=&quot;select ' + (field.cls ? field.cls : &quot;&quot;) + '&quot;'</td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source">      + ' id=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source">      + (field.multiple ? ' multiple=&quot;multiple&quot;' : '')</td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source">      + '&gt;';</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">330</td><td class="hits">0</td><td class="source">      var options = typeof field.options === 'function' ? field.options() : field.options;</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">332</td><td class="hits">0</td><td class="source">      if(field.optgroups){</td></tr><tr class="miss"><td class="line">333</td><td class="hits">0</td><td class="source">        field.optgroups.forEach(function(optgroup){</td></tr><tr class="miss"><td class="line">334</td><td class="hits">0</td><td class="source">          tagOutput += '&lt;optgroup label=&quot;' + optgroup.label + '&quot;&gt;';</td></tr><tr class="miss"><td class="line">335</td><td class="hits">0</td><td class="source">          optgroup.options.forEach(function(option){</td></tr><tr class="miss"><td class="line">336</td><td class="hits">0</td><td class="source">            tagOutput += me.elementTypes.option.render(option, value, 'select');</td></tr><tr><td class="line">337</td><td class="hits"></td><td class="source">          });</td></tr><tr class="miss"><td class="line">338</td><td class="hits">0</td><td class="source">          tagOutput += '&lt;/optgroup&gt;';</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">341</td><td class="hits">0</td><td class="source">        options.forEach(function(option){</td></tr><tr class="miss"><td class="line">342</td><td class="hits">0</td><td class="source">          tagOutput += me.elementTypes.option.render(option, value, 'select');</td></tr><tr><td class="line">343</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">344</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">345</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;/select&gt;';</td></tr><tr><td class="line">346</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">347</td><td class="hits">0</td><td class="source">      return me.decorateField(field, tagOutput);</td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">350</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source">  'optgroup': {</td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source">    canBeContainedBy: ['select'],</td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source">    canContain: ['option']</td></tr><tr><td class="line">354</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source">  'options': {</td></tr><tr><td class="line">357</td><td class="hits"></td><td class="source">    canBeContainedBy: ['select'],</td></tr><tr><td class="line">358</td><td class="hits"></td><td class="source">    canContain: ['option']</td></tr><tr><td class="line">359</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">360</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">361</td><td class="hits"></td><td class="source">  // an &quot;option&quot; can be an &lt;option&gt; or a radio or a checkbox.</td></tr><tr><td class="line">362</td><td class="hits"></td><td class="source">  'option': {</td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source">    canBeContainedBy: ['radios','checkboxes','select','optgroup'],</td></tr><tr><td class="line">364</td><td class="hits"></td><td class="source">    // container determines render method.</td></tr><tr><td class="line">365</td><td class="hits"></td><td class="source">    render: function(option, value, containerType){</td></tr><tr class="miss"><td class="line">366</td><td class="hits">0</td><td class="source">      if(containerType == 'select'){</td></tr><tr class="miss"><td class="line">367</td><td class="hits">0</td><td class="source">        var displayText = option.label || option;</td></tr><tr class="miss"><td class="line">368</td><td class="hits">0</td><td class="source">        var optionValue = option.value || option;</td></tr><tr class="miss"><td class="line">369</td><td class="hits">0</td><td class="source">        return (</td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source">          '&lt;option'</td></tr><tr><td class="line">371</td><td class="hits"></td><td class="source">          + ' value=&quot;' + optionValue + '&quot;'</td></tr><tr><td class="line">372</td><td class="hits"></td><td class="source">          + (value === optionValue ? ' selected' : '')</td></tr><tr><td class="line">373</td><td class="hits"></td><td class="source">          + (option.cls ? ' class=&quot;' + option.cls + '&quot;' : '')</td></tr><tr><td class="line">374</td><td class="hits"></td><td class="source">          + '&gt;'</td></tr><tr><td class="line">375</td><td class="hits"></td><td class="source">          + displayText</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source">          + '&lt;/option&gt;'</td></tr><tr><td class="line">377</td><td class="hits"></td><td class="source">        );</td></tr><tr><td class="line">378</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">379</td><td class="hits">0</td><td class="source">        return me.defaultTagRenderer(option, value);</td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">381</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">382</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">383</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">384</td><td class="hits"></td><td class="source">  // type: 'radio' should become type: option, and be in a {type: radios}</td></tr><tr><td class="line">385</td><td class="hits"></td><td class="source">  'radio': {</td></tr><tr><td class="line">386</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">387</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">388</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">389</td><td class="hits"></td><td class="source">  // type: 'checkbox' should become type: option, and be in a {type: checkboxes}</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source">  'checkbox': {</td></tr><tr><td class="line">391</td><td class="hits"></td><td class="source">    render: function(field, value, bare) {</td></tr><tr><td class="line">392</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">393</td><td class="hits"></td><td class="source">      // Quickly flip values to true/false if on/off</td></tr><tr class="miss"><td class="line">394</td><td class="hits">0</td><td class="source">      value = (value === &quot;on&quot; ? true : (value === &quot;off&quot; ? false : value));</td></tr><tr><td class="line">395</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">396</td><td class="hits"></td><td class="source">      // Now set the checked variable</td></tr><tr class="miss"><td class="line">397</td><td class="hits">0</td><td class="source">      var checked = (value ? true : (field.value ? true : (field.checked ? true : false)));</td></tr><tr><td class="line">398</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">399</td><td class="hits">0</td><td class="source">      var tagOutput = &quot;&quot;;</td></tr><tr><td class="line">400</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">401</td><td class="hits">0</td><td class="source">      if(!field.readonly &amp;&amp; !field.disabled){</td></tr><tr><td class="line">402</td><td class="hits"></td><td class="source">        // Workaround for readonly/disabled fields (esp. checkboxes/radios) - add a hidden field with the value</td></tr><tr class="miss"><td class="line">403</td><td class="hits">0</td><td class="source">        tagOutput += '&lt;input type=&quot;hidden&quot; name=&quot;' + field.name + '&quot; value=&quot;off&quot; /&gt;';</td></tr><tr><td class="line">404</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">405</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">406</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;input type=&quot;' + field.type + '&quot;'</td></tr><tr><td class="line">407</td><td class="hits"></td><td class="source">      + ' class=&quot;'+ field.type + (field.cls ? ' ' + field.cls : &quot;&quot;) + (field.labelFirst ? ' labelFirst' : '') + '&quot;'</td></tr><tr><td class="line">408</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">409</td><td class="hits"></td><td class="source">      + ' id=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">410</td><td class="hits"></td><td class="source">      + (field.readonly || field.disabled ? ' disabled' : '')</td></tr><tr><td class="line">411</td><td class="hits"></td><td class="source">      + (checked ? ' checked' : '')</td></tr><tr><td class="line">412</td><td class="hits"></td><td class="source">      + f.tagClose;</td></tr><tr><td class="line">413</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">414</td><td class="hits">0</td><td class="source">      if(field.readonly || field.disabled){</td></tr><tr><td class="line">415</td><td class="hits"></td><td class="source">        // Workaround for readonly/disabled fields (esp. checkboxes/radios) - add a hidden field with the value</td></tr><tr class="miss"><td class="line">416</td><td class="hits">0</td><td class="source">        tagOutput += '&lt;input type=&quot;hidden&quot; name=&quot;' + field.name + '&quot; value=&quot;' + (checked ? &quot;on&quot; : &quot;off&quot;) + '&quot; /&gt;';</td></tr><tr><td class="line">417</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">418</td><td class="hits">0</td><td class="source">      return bare ? tagOutput : me.decorateField(field, tagOutput);</td></tr><tr><td class="line">419</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">420</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">421</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">422</td><td class="hits"></td><td class="source">  'text': {</td></tr><tr><td class="line">423</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">424</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">425</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">426</td><td class="hits"></td><td class="source">  'textarea': {</td></tr><tr><td class="line">427</td><td class="hits"></td><td class="source">    render: function(field, value){</td></tr><tr class="miss"><td class="line">428</td><td class="hits">0</td><td class="source">      return me.decorateField(field, '&lt;textarea'</td></tr><tr><td class="line">429</td><td class="hits"></td><td class="source">      + ' class=&quot;textarea ' + (field.cls ? field.cls : &quot;&quot;) + '&quot;'</td></tr><tr><td class="line">430</td><td class="hits"></td><td class="source">      + ' rows=&quot;' + (field.rows ? field.rows : &quot;10&quot;) + '&quot;'</td></tr><tr><td class="line">431</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">432</td><td class="hits"></td><td class="source">      + ' id=&quot;' + field.name + '&quot;'</td></tr><tr><td class="line">433</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">434</td><td class="hits"></td><td class="source">      + '&gt;'</td></tr><tr><td class="line">435</td><td class="hits"></td><td class="source">      + value</td></tr><tr><td class="line">436</td><td class="hits"></td><td class="source">      + '&lt;/textarea&gt;');</td></tr><tr><td class="line">437</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">438</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">439</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">440</td><td class="hits"></td><td class="source">  'hidden': {</td></tr><tr><td class="line">441</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">442</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">443</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">444</td><td class="hits"></td><td class="source">  'password': {  // can be special, if there is a 'verify'</td></tr><tr><td class="line">445</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">446</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">447</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">448</td><td class="hits"></td><td class="source">  // might allow file to take a url</td></tr><tr><td class="line">449</td><td class="hits"></td><td class="source">  'file': {</td></tr><tr><td class="line">450</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">451</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">452</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">453</td><td class="hits"></td><td class="source">  'buttons': {</td></tr><tr><td class="line">454</td><td class="hits"></td><td class="source">    canContain: ['submit','image','reset','button','link']</td></tr><tr><td class="line">455</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">456</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">457</td><td class="hits"></td><td class="source">  // buttons should only be able to be added to the 'action set'</td></tr><tr><td class="line">458</td><td class="hits"></td><td class="source">  // button can be [submit, reset, cancel (a link), button (generic), link (generic)]</td></tr><tr><td class="line">459</td><td class="hits"></td><td class="source">  // if form has pages, 'previous' and 'next' buttons should interpolate until the last page, 'submit'</td></tr><tr><td class="line">460</td><td class="hits"></td><td class="source">  'button': {</td></tr><tr><td class="line">461</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">462</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">463</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">464</td><td class="hits"></td><td class="source">  'submit': {</td></tr><tr><td class="line">465</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">466</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">467</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">468</td><td class="hits"></td><td class="source">  'image': {</td></tr><tr><td class="line">469</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">470</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">471</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">472</td><td class="hits"></td><td class="source">  'reset': {</td></tr><tr><td class="line">473</td><td class="hits"></td><td class="source">    render: me.defaultTagRenderer</td></tr><tr><td class="line">474</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">475</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">476</td><td class="hits"></td><td class="source">  // a link is not really a form control, but is provided here for convenience</td></tr><tr><td class="line">477</td><td class="hits"></td><td class="source">  // it also doesn't really make sense for it to have a value.</td></tr><tr><td class="line">478</td><td class="hits"></td><td class="source">  // a link should have an href and text, and optionally, cls ('class'), id</td></tr><tr><td class="line">479</td><td class="hits"></td><td class="source">  'link': {</td></tr><tr><td class="line">480</td><td class="hits"></td><td class="source">    render: function(field, value){</td></tr><tr class="miss"><td class="line">481</td><td class="hits">0</td><td class="source">      var id = field.id || field.name;</td></tr><tr class="miss"><td class="line">482</td><td class="hits">0</td><td class="source">      var text = field.text || field.value;</td></tr><tr class="miss"><td class="line">483</td><td class="hits">0</td><td class="source">      return '&lt;a href=&quot;' + field.href + '&quot;'</td></tr><tr><td class="line">484</td><td class="hits"></td><td class="source">        + ' class=&quot;form-link' + (field.cls ? ' ' + field.cls : &quot;&quot;) + '&quot;'</td></tr><tr><td class="line">485</td><td class="hits"></td><td class="source">        + (id ? ' id=&quot;' + id + '&quot;' : '')</td></tr><tr><td class="line">486</td><td class="hits"></td><td class="source">        + '&gt;' + text + '&lt;/a&gt;';</td></tr><tr><td class="line">487</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">488</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">489</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">490</td><td class="hits"></td><td class="source">  'date': {</td></tr><tr><td class="line">491</td><td class="hits"></td><td class="source">    render: function(field, value, bare){</td></tr><tr><td class="line">492</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">493</td><td class="hits">0</td><td class="source">      if(!value) {</td></tr><tr class="miss"><td class="line">494</td><td class="hits">0</td><td class="source">        value = new Date();</td></tr><tr><td class="line">495</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">496</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">497</td><td class="hits"></td><td class="source">      // TODO - use user's Locale</td></tr><tr class="miss"><td class="line">498</td><td class="hits">0</td><td class="source">      var monthNames = calipso.date.regional[''].monthNamesShort;</td></tr><tr><td class="line">499</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">500</td><td class="hits">0</td><td class="source">      var tagOutput = '&lt;input type=&quot;text&quot;'</td></tr><tr><td class="line">501</td><td class="hits"></td><td class="source">      + ' class=&quot;date date-day' + (field.cls ? ' date-day-'+field.cls : '') + '&quot;'</td></tr><tr><td class="line">502</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '[day]&quot;'</td></tr><tr><td class="line">503</td><td class="hits"></td><td class="source">      + ' value=&quot;' + value.getDate() + '&quot;'</td></tr><tr><td class="line">504</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">505</td><td class="hits"></td><td class="source">      + f.tagClose;</td></tr><tr><td class="line">506</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">507</td><td class="hits">0</td><td class="source">      tagOutput += ' ';</td></tr><tr><td class="line">508</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">509</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;select class=&quot;date date-month' + (field.cls ? ' date-month-'+field.cls : '') + '&quot;'</td></tr><tr><td class="line">510</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">511</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '[month]&quot;&gt;';</td></tr><tr class="miss"><td class="line">512</td><td class="hits">0</td><td class="source">      for(var monthNameCounter=0; monthNameCounter&lt;12; monthNameCounter++) {</td></tr><tr class="miss"><td class="line">513</td><td class="hits">0</td><td class="source">        tagOutput += (</td></tr><tr><td class="line">514</td><td class="hits"></td><td class="source">          '&lt;option value=&quot;'+monthNameCounter+'&quot;' + (value.getMonth() === monthNameCounter ? ' selected' : '') + '&gt;'</td></tr><tr><td class="line">515</td><td class="hits"></td><td class="source">          + monthNames[monthNameCounter]</td></tr><tr><td class="line">516</td><td class="hits"></td><td class="source">          + '&lt;/option&gt;'</td></tr><tr><td class="line">517</td><td class="hits"></td><td class="source">        );</td></tr><tr><td class="line">518</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">519</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;/select&gt;';</td></tr><tr><td class="line">520</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">521</td><td class="hits">0</td><td class="source">      tagOutput += ' ';</td></tr><tr><td class="line">522</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">523</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;input type=&quot;text&quot;'</td></tr><tr><td class="line">524</td><td class="hits"></td><td class="source">      + ' class=&quot;date date-year' + (field.cls ? ' date-year-'+field.cls : '') + '&quot;'</td></tr><tr><td class="line">525</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '[year]&quot;'</td></tr><tr><td class="line">526</td><td class="hits"></td><td class="source">      + ' value=&quot;' + value.getFullYear() + '&quot;'</td></tr><tr><td class="line">527</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">528</td><td class="hits"></td><td class="source">      + f.tagClose;</td></tr><tr><td class="line">529</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">530</td><td class="hits">0</td><td class="source">      return bare ? tagOutput : me.decorateField(field, tagOutput);</td></tr><tr><td class="line">531</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">532</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">533</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">534</td><td class="hits"></td><td class="source">  'time': {</td></tr><tr><td class="line">535</td><td class="hits"></td><td class="source">    render: function(field, value, bare) {</td></tr><tr><td class="line">536</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">537</td><td class="hits"></td><td class="source">      // TODO</td></tr><tr class="miss"><td class="line">538</td><td class="hits">0</td><td class="source">      if(!value) {</td></tr><tr class="miss"><td class="line">539</td><td class="hits">0</td><td class="source">        value = new Date(); // why 1900? why not 'now'?</td></tr><tr><td class="line">540</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">541</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">542</td><td class="hits">0</td><td class="source">      var tagOutput = '&lt;input type=&quot;text&quot; class=&quot;time time-hours' + (field.cls ? ' time-hours-'+field.cls : '') + '&quot;'</td></tr><tr><td class="line">543</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '[hours]&quot;'</td></tr><tr><td class="line">544</td><td class="hits"></td><td class="source">      + ' value=&quot;' + value.getHours() + '&quot;'</td></tr><tr><td class="line">545</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">546</td><td class="hits"></td><td class="source">      + f.tagClose;</td></tr><tr><td class="line">547</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">548</td><td class="hits">0</td><td class="source">      tagOutput += ' ';</td></tr><tr><td class="line">549</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">550</td><td class="hits">0</td><td class="source">      tagOutput += '&lt;input type=&quot;text&quot; class=&quot;time time-minutes' + (field.cls ? ' time-minutes-'+field.cls : '') + '&quot;'</td></tr><tr><td class="line">551</td><td class="hits"></td><td class="source">      + ' name=&quot;' + field.name + '[minutes]&quot;'</td></tr><tr><td class="line">552</td><td class="hits"></td><td class="source">      + ' value=&quot;' + value.getMinutes() + '&quot;'</td></tr><tr><td class="line">553</td><td class="hits"></td><td class="source">      + (field.required ? ' required' : '')</td></tr><tr><td class="line">554</td><td class="hits"></td><td class="source">      + f.tagClose;</td></tr><tr><td class="line">555</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">556</td><td class="hits">0</td><td class="source">      return bare ? tagOutput : me.decorateField(field, tagOutput);</td></tr><tr><td class="line">557</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">558</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">559</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">560</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">561</td><td class="hits"></td><td class="source">  'datetime': {</td></tr><tr><td class="line">562</td><td class="hits"></td><td class="source">    render: function(field, value) {</td></tr><tr><td class="line">563</td><td class="hits"></td><td class="source">      // Call both types</td></tr><tr class="miss"><td class="line">564</td><td class="hits">0</td><td class="source">      return me.decorateField(field,</td></tr><tr><td class="line">565</td><td class="hits"></td><td class="source">        me.elementTypes.date.render({</td></tr><tr><td class="line">566</td><td class="hits"></td><td class="source">          name: field.name,</td></tr><tr><td class="line">567</td><td class="hits"></td><td class="source">          type: &quot;date&quot;,</td></tr><tr><td class="line">568</td><td class="hits"></td><td class="source">          required: field.required</td></tr><tr><td class="line">569</td><td class="hits"></td><td class="source">        }, value, true) +</td></tr><tr><td class="line">570</td><td class="hits"></td><td class="source">        ' ' +</td></tr><tr><td class="line">571</td><td class="hits"></td><td class="source">        me.elementTypes.time.render({</td></tr><tr><td class="line">572</td><td class="hits"></td><td class="source">          name: field.name,</td></tr><tr><td class="line">573</td><td class="hits"></td><td class="source">          type: &quot;time&quot;,</td></tr><tr><td class="line">574</td><td class="hits"></td><td class="source">          required: field.required</td></tr><tr><td class="line">575</td><td class="hits"></td><td class="source">        }, value, true)</td></tr><tr><td class="line">576</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">577</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">578</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">579</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">580</td><td class="hits"></td><td class="source">  'crontime': {</td></tr><tr><td class="line">581</td><td class="hits"></td><td class="source">    render: function(field, value) {</td></tr><tr class="miss"><td class="line">582</td><td class="hits">0</td><td class="source">      var tagOutput = '';</td></tr><tr class="miss"><td class="line">583</td><td class="hits">0</td><td class="source">      var cronTimeValues = value ? value.split(/\s/) : ['*','*','*','*','*','*'];</td></tr><tr class="miss"><td class="line">584</td><td class="hits">0</td><td class="source">      for(var cronTimeInputCounter = 0; cronTimeInputCounter &lt; 6; cronTimeInputCounter++) {</td></tr><tr class="miss"><td class="line">585</td><td class="hits">0</td><td class="source">        tagOutput += (</td></tr><tr><td class="line">586</td><td class="hits"></td><td class="source">          '&lt;input type=&quot;text&quot; class=&quot;text crontime&quot; value=&quot;' +</td></tr><tr><td class="line">587</td><td class="hits"></td><td class="source">          cronTimeValues[cronTimeInputCounter] +</td></tr><tr><td class="line">588</td><td class="hits"></td><td class="source">          '&quot; name=&quot;job[cronTime' + cronTimeInputCounter + ']&quot;' +</td></tr><tr><td class="line">589</td><td class="hits"></td><td class="source">          (field.required ? ' required' : '') +</td></tr><tr><td class="line">590</td><td class="hits"></td><td class="source">          f.tagClose</td></tr><tr><td class="line">591</td><td class="hits"></td><td class="source">        );</td></tr><tr><td class="line">592</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">593</td><td class="hits">0</td><td class="source">      return me.decorateField(field, tagOutput);</td></tr><tr><td class="line">594</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">595</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">596</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">597</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">598</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">599</td><td class="hits"></td><td class="source">// any element types that reference other element types have to be declared afterward</td></tr><tr><td class="line">600</td><td class="hits"></td><td class="source">// so that the references exist.</td></tr><tr class="hit"><td class="line">601</td><td class="hits">1</td><td class="source">me.elementTypes.richtext = {</td></tr><tr><td class="line">602</td><td class="hits"></td><td class="source">  render: me.elementTypes.textarea.render</td></tr><tr><td class="line">603</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">604</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">605</td><td class="hits">1</td><td class="source">me.elementTypes.json = {</td></tr><tr><td class="line">606</td><td class="hits"></td><td class="source">  render: me.elementTypes.textarea.render</td></tr><tr><td class="line">607</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">608</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">609</td><td class="hits">1</td><td class="source">me.elementTypes.email = {</td></tr><tr><td class="line">610</td><td class="hits"></td><td class="source">  render: function(field, value){</td></tr><tr><td class="line">611</td><td class="hits"></td><td class="source">    //var _field = copyProperties(field, {});</td></tr><tr><td class="line">612</td><td class="hits"></td><td class="source">    //_field.type = 'text';</td></tr><tr class="miss"><td class="line">613</td><td class="hits">0</td><td class="source">    field.type = 'text';</td></tr><tr class="miss"><td class="line">614</td><td class="hits">0</td><td class="source">    field.cls = (field.cls ? field.cls + ' ' : '') + 'email';</td></tr><tr class="miss"><td class="line">615</td><td class="hits">0</td><td class="source">    me.elementTypes.textarea.render(field, value);</td></tr><tr><td class="line">616</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">617</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">618</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">619</td><td class="hits">1</td><td class="source">me.elementTypes.address = {</td></tr><tr><td class="line">620</td><td class="hits"></td><td class="source">  render: me.elementTypes.fieldset.render,</td></tr><tr><td class="line">621</td><td class="hits"></td><td class="source">  defaultDefinition: {</td></tr><tr><td class="line">622</td><td class="hits"></td><td class="source">    tag: 'fieldset',</td></tr><tr><td class="line">623</td><td class="hits"></td><td class="source">    type: 'address',</td></tr><tr><td class="line">624</td><td class="hits"></td><td class="source">    children: [</td></tr><tr><td class="line">625</td><td class="hits"></td><td class="source">      {type: 'text', name: 'street', label: 'Street Address'},</td></tr><tr><td class="line">626</td><td class="hits"></td><td class="source">      {type: 'select', name: 'country', label: 'Country', options: me.countries},</td></tr><tr><td class="line">627</td><td class="hits"></td><td class="source">      {type: 'select', name: 'state', label: 'State', options: me.states[&quot;United States&quot;]},</td></tr><tr><td class="line">628</td><td class="hits"></td><td class="source">      {type: 'text', name: 'postalcode', label: 'Postal Code'}</td></tr><tr><td class="line">629</td><td class="hits"></td><td class="source">    ]</td></tr><tr><td class="line">630</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">631</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">632</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">633</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">634</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">635</td><td class="hits"></td><td class="source"> * Form Renderer, controls the overall creation of the form based on a form json object passed</td></tr><tr><td class="line">636</td><td class="hits"></td><td class="source"> * in as the first parameter.  The structure of this object is as follows:</td></tr><tr><td class="line">637</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">638</td><td class="hits"></td><td class="source"> *     form</td></tr><tr><td class="line">639</td><td class="hits"></td><td class="source"> *        id : Unique ID that will become the form ID.</td></tr><tr><td class="line">640</td><td class="hits"></td><td class="source"> *        title : Title to show at the top of the form.</td></tr><tr><td class="line">641</td><td class="hits"></td><td class="source"> *        type : Type of form (not used at present).</td></tr><tr><td class="line">642</td><td class="hits"></td><td class="source"> *        method: HTTP method to use.</td></tr><tr><td class="line">643</td><td class="hits"></td><td class="source"> *        action : URL to submit form to.</td></tr><tr><td class="line">644</td><td class="hits"></td><td class="source"> *        tabs : Should tabs be rendered for sections (default false).</td></tr><tr><td class="line">645</td><td class="hits"></td><td class="source"> *      sections [*] : Optional - divide the form into sections.</td></tr><tr><td class="line">646</td><td class="hits"></td><td class="source"> *        id  : Unique identifier for a section.</td></tr><tr><td class="line">647</td><td class="hits"></td><td class="source"> *        label : Description of section (appears as header or tab label)</td></tr><tr><td class="line">648</td><td class="hits"></td><td class="source"> *        fields [*] : Array of fields in the section (see below).</td></tr><tr><td class="line">649</td><td class="hits"></td><td class="source"> *      fields [*] : Form fields array - can be in form or section.</td></tr><tr><td class="line">650</td><td class="hits"></td><td class="source"> *        label : Label for form field.</td></tr><tr><td class="line">651</td><td class="hits"></td><td class="source"> *        name : Name of form element to be passed back with the value.</td></tr><tr><td class="line">652</td><td class="hits"></td><td class="source"> *        type : Type of element, based on the form functions defined below.</td></tr><tr><td class="line">653</td><td class="hits"></td><td class="source"> *        description : Description text to be rendered after the element in a div tag.</td></tr><tr><td class="line">654</td><td class="hits"></td><td class="source"> *      buttons [*] : Array of buttons to be rendered at the bottom of the form.</td></tr><tr><td class="line">655</td><td class="hits"></td><td class="source"> *        name : Name of button (for submission).</td></tr><tr><td class="line">656</td><td class="hits"></td><td class="source"> *        type : Type of button.</td></tr><tr><td class="line">657</td><td class="hits"></td><td class="source"> *        value : Value to submit when pressed.</td></tr><tr><td class="line">658</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">659</td><td class="hits"></td><td class="source"> * A complete example is shown below:</td></tr><tr><td class="line">660</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">661</td><td class="hits"></td><td class="source"> *      var myForm = {id:'my-form',title:'Create My Thing...',type:'form',method:'POST',action:'/myaction',tabs:false,</td></tr><tr><td class="line">662</td><td class="hits"></td><td class="source"> *          sections:[{</td></tr><tr><td class="line">663</td><td class="hits"></td><td class="source"> *            id:'myform-section-1',</td></tr><tr><td class="line">664</td><td class="hits"></td><td class="source"> *            label:'Section 1',</td></tr><tr><td class="line">665</td><td class="hits"></td><td class="source"> *            fields:[</td></tr><tr><td class="line">666</td><td class="hits"></td><td class="source"> *                    {label:'Field A',name:'object[fieldA]',type:'text',description:'Description ... '},</td></tr><tr><td class="line">667</td><td class="hits"></td><td class="source"> *                    {label:'Field B',name:'object[fieldB]',type:'textarea',description:'Description ...'}</td></tr><tr><td class="line">668</td><td class="hits"></td><td class="source"> *                   ]</td></tr><tr><td class="line">669</td><td class="hits"></td><td class="source"> *          },{</td></tr><tr><td class="line">670</td><td class="hits"></td><td class="source"> *            id:'myform-section2',</td></tr><tr><td class="line">671</td><td class="hits"></td><td class="source"> *            label:'Section 2',</td></tr><tr><td class="line">672</td><td class="hits"></td><td class="source"> *            fields:[</td></tr><tr><td class="line">673</td><td class="hits"></td><td class="source"> *                    {label:'Select Field',name:'object[select]',type:'select',options:[&quot;option 1&quot;,&quot;option 2&quot;],description:'Description...'},</td></tr><tr><td class="line">674</td><td class="hits"></td><td class="source"> *                    {label:'Date Field',name:'object[date]',type:'datetime',description:'Description...'},</td></tr><tr><td class="line">675</td><td class="hits"></td><td class="source"> *                   ]</td></tr><tr><td class="line">676</td><td class="hits"></td><td class="source"> *          }</td></tr><tr><td class="line">677</td><td class="hits"></td><td class="source"> *          ],</td></tr><tr><td class="line">678</td><td class="hits"></td><td class="source"> *          fields:[</td></tr><tr><td class="line">679</td><td class="hits"></td><td class="source"> *            {label:'',name:'hiddenField',type:'hidden'}</td></tr><tr><td class="line">680</td><td class="hits"></td><td class="source"> *          ],</td></tr><tr><td class="line">681</td><td class="hits"></td><td class="source"> *          buttons:[</td></tr><tr><td class="line">682</td><td class="hits"></td><td class="source"> *               {name:'submit',type:'submit',value:'Save'}</td></tr><tr><td class="line">683</td><td class="hits"></td><td class="source"> *          ]};</td></tr><tr><td class="line">684</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">685</td><td class="hits"></td><td class="source"> * The values of the form are passed through (optionally) as the second parameter.  This allows you to re-use</td></tr><tr><td class="line">686</td><td class="hits"></td><td class="source"> * a form definition across different uses (e.g. CRU).</td></tr><tr><td class="line">687</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">688</td><td class="hits"></td><td class="source"> * @param item : the json object representing the form</td></tr><tr><td class="line">689</td><td class="hits"></td><td class="source"> * @param values : The values to initialise the form with</td></tr><tr><td class="line">690</td><td class="hits"></td><td class="source"> * @param next : Callback when done, pass markup as return val (TODO : deprecate this, then can use form.render in views)</td></tr><tr><td class="line">691</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">692</td><td class="hits">1</td><td class="source">me.render = function(formJson, values, req, next) {</td></tr><tr><td class="line">693</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">694</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr><td class="line">695</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">696</td><td class="hits"></td><td class="source">  // Store local reference to the request for use during translation</td></tr><tr class="miss"><td class="line">697</td><td class="hits">0</td><td class="source">  t = req.t;</td></tr><tr><td class="line">698</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">699</td><td class="hits"></td><td class="source">  // Emit a form pre-render event.</td></tr><tr class="miss"><td class="line">700</td><td class="hits">0</td><td class="source">  calipso.e.custom_emit('FORM', formJson.id, formJson, function(formJson) {</td></tr><tr><td class="line">701</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">702</td><td class="hits">0</td><td class="source">      var form = (</td></tr><tr><td class="line">703</td><td class="hits"></td><td class="source">        self.start_form(formJson) +</td></tr><tr><td class="line">704</td><td class="hits"></td><td class="source">        self.render_sections(formJson, values) + // todo: deprecate - sections should be treated the same as any other field (container)</td></tr><tr><td class="line">705</td><td class="hits"></td><td class="source">        self.render_fields(formJson, values) +</td></tr><tr><td class="line">706</td><td class="hits"></td><td class="source">        self.render_buttons(formJson.buttons) + // todo: deprecate - buttons should be treated the same as any other field (container)</td></tr><tr><td class="line">707</td><td class="hits"></td><td class="source">        self.end_form(formJson)</td></tr><tr><td class="line">708</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">709</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">710</td><td class="hits"></td><td class="source">      // Save the form object in session, this enables us to use it later</td></tr><tr><td class="line">711</td><td class="hits"></td><td class="source">      // To parse the incoming data and validate against.</td></tr><tr><td class="line">712</td><td class="hits"></td><td class="source">      // Saving it in the session allows for per-user customisation of the form without</td></tr><tr><td class="line">713</td><td class="hits"></td><td class="source">      // impacting this code.</td></tr><tr class="miss"><td class="line">714</td><td class="hits">0</td><td class="source">      saveFormInSession(formJson, req, function(err) {</td></tr><tr class="miss"><td class="line">715</td><td class="hits">0</td><td class="source">        if(err) calipso.error(err.message);</td></tr><tr class="miss"><td class="line">716</td><td class="hits">0</td><td class="source">        next(form);</td></tr><tr><td class="line">717</td><td class="hits"></td><td class="source">      })</td></tr><tr><td class="line">718</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">719</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">720</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">721</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">722</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">723</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">724</td><td class="hits"></td><td class="source"> * Helper to save a form in the session to be used later when processing.</td></tr><tr><td class="line">725</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">726</td><td class="hits">1</td><td class="source">function saveFormInSession(form, req, next) {</td></tr><tr><td class="line">727</td><td class="hits"></td><td class="source">  </td></tr><tr><td class="line">728</td><td class="hits"></td><td class="source">  // If we have a form id and a session, save it</td></tr><tr class="miss"><td class="line">729</td><td class="hits">0</td><td class="source">  if(form.id &amp;&amp; calipso.lib._.keys(req.session).length &gt; 0) {</td></tr><tr class="miss"><td class="line">730</td><td class="hits">0</td><td class="source">    calipso.silly(&quot;Saving form &quot; + form.id + &quot; in session.&quot;);</td></tr><tr class="miss"><td class="line">731</td><td class="hits">0</td><td class="source">    req.session.forms = req.session.forms || {};</td></tr><tr class="miss"><td class="line">732</td><td class="hits">0</td><td class="source">    req.session.forms[form.id] = form;</td></tr><tr class="miss"><td class="line">733</td><td class="hits">0</td><td class="source">    req.session.save(next);</td></tr><tr><td class="line">734</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">735</td><td class="hits">0</td><td class="source">    next();</td></tr><tr><td class="line">736</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">737</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">738</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">739</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">740</td><td class="hits"></td><td class="source"> * Deal with form tabs in jQuery UI style if required.</td></tr><tr><td class="line">741</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">742</td><td class="hits">1</td><td class="source">me.formTabs = function(sections) {</td></tr><tr><td class="line">743</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">744</td><td class="hits">0</td><td class="source">  if(!sections)</td></tr><tr class="miss"><td class="line">745</td><td class="hits">0</td><td class="source">    return '';</td></tr><tr><td class="line">746</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">747</td><td class="hits">0</td><td class="source">  var tabOutput = '&lt;nav&gt;&lt;ul class=&quot;tabs&quot;&gt;',</td></tr><tr><td class="line">748</td><td class="hits"></td><td class="source">    numSections = sections.length;</td></tr><tr><td class="line">749</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">750</td><td class="hits">0</td><td class="source">  sections.forEach( function(section, index) {</td></tr><tr class="miss"><td class="line">751</td><td class="hits">0</td><td class="source">    var classes = 'form-tab';</td></tr><tr class="miss"><td class="line">752</td><td class="hits">0</td><td class="source">    if (index === 0) {</td></tr><tr class="miss"><td class="line">753</td><td class="hits">0</td><td class="source">      classes += ' first';</td></tr><tr><td class="line">754</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">755</td><td class="hits">0</td><td class="source">    if ((index + 1) === numSections) {</td></tr><tr class="miss"><td class="line">756</td><td class="hits">0</td><td class="source">      classes += ' last';</td></tr><tr><td class="line">757</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">758</td><td class="hits">0</td><td class="source">    tabOutput += '&lt;li class=&quot;' + classes + '&quot;&gt;&lt;a href=&quot;#' + section.id + '&quot;&gt;' + t(section.label) + '&lt;/a&gt;&lt;/li&gt;';</td></tr><tr><td class="line">759</td><td class="hits"></td><td class="source">  });</td></tr><tr class="miss"><td class="line">760</td><td class="hits">0</td><td class="source">  return tabOutput + '&lt;/ul&gt;&lt;/nav&gt;';</td></tr><tr><td class="line">761</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">762</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">763</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">764</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">765</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">766</td><td class="hits"></td><td class="source"> * Render the initial form tag</td></tr><tr><td class="line">767</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">768</td><td class="hits"></td><td class="source"> * @param form</td></tr><tr><td class="line">769</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">770</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">771</td><td class="hits">1</td><td class="source">me.start_form = function(form) {</td></tr><tr class="miss"><td class="line">772</td><td class="hits">0</td><td class="source">  return (</td></tr><tr><td class="line">773</td><td class="hits"></td><td class="source">    '&lt;form id=&quot;' + form.id + '&quot; name=&quot;' + form.id + '&quot;' + (form.cls ? ' class=&quot;' + form.cls + '&quot;' : &quot;&quot;) +</td></tr><tr><td class="line">774</td><td class="hits"></td><td class="source">    ' method=&quot;' + form.method + '&quot;' + ' enctype=&quot;' + (form.enctype ? form.enctype : &quot;multipart/form-data&quot;) + '&quot;' + ' action=&quot;' + form.action + '&quot;&gt;' +</td></tr><tr><td class="line">775</td><td class="hits"></td><td class="source">    '&lt;input type=&quot;hidden&quot; value=&quot;' + form.id + '&quot; name=&quot;form[id]&quot;/&gt;' +</td></tr><tr><td class="line">776</td><td class="hits"></td><td class="source">    '&lt;header class=&quot;form-header&quot;&gt;' +</td></tr><tr><td class="line">777</td><td class="hits"></td><td class="source">    '&lt;h2&gt;' + t(form.title) + '&lt;/h2&gt;' +</td></tr><tr><td class="line">778</td><td class="hits"></td><td class="source">    '&lt;/header&gt;' +</td></tr><tr><td class="line">779</td><td class="hits"></td><td class="source">    '&lt;div class=&quot;form-container&quot;&gt;' +</td></tr><tr><td class="line">780</td><td class="hits"></td><td class="source">    (form.tabs ? this.formTabs(form.sections) : '') +</td></tr><tr><td class="line">781</td><td class="hits"></td><td class="source">    '&lt;div class=&quot;form-fields'+(form.tabs ? ' tab-container' : '')+'&quot;&gt;'</td></tr><tr><td class="line">782</td><td class="hits"></td><td class="source">  );</td></tr><tr><td class="line">783</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">784</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">785</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">786</td><td class="hits"></td><td class="source"> * Close the form</td></tr><tr><td class="line">787</td><td class="hits"></td><td class="source"> * @param form</td></tr><tr><td class="line">788</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">789</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">790</td><td class="hits">1</td><td class="source">me.end_form = function(form) {</td></tr><tr class="miss"><td class="line">791</td><td class="hits">0</td><td class="source">  return '&lt;/div&gt;&lt;/div&gt;&lt;/form&gt;';</td></tr><tr><td class="line">792</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">793</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">794</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">795</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">796</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">797</td><td class="hits"></td><td class="source"> * Render the form sections, iterating through and then rendering</td></tr><tr><td class="line">798</td><td class="hits"></td><td class="source"> * each of the fields within a section.</td></tr><tr><td class="line">799</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">800</td><td class="hits">1</td><td class="source">me.render_sections = function(form, values) {</td></tr><tr><td class="line">801</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">802</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr class="miss"><td class="line">803</td><td class="hits">0</td><td class="source">  var sections = form.sections;</td></tr><tr><td class="line">804</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">805</td><td class="hits">0</td><td class="source">  if(!sections)</td></tr><tr class="miss"><td class="line">806</td><td class="hits">0</td><td class="source">    return '';</td></tr><tr><td class="line">807</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">808</td><td class="hits">0</td><td class="source">  var sectionOutput = '';</td></tr><tr><td class="line">809</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">810</td><td class="hits">0</td><td class="source">  sections.forEach(function(section) {</td></tr><tr class="miss"><td class="line">811</td><td class="hits">0</td><td class="source">    sectionOutput += (</td></tr><tr><td class="line">812</td><td class="hits"></td><td class="source">      '&lt;section' + (form.tabs?' class=&quot;tab-content&quot;':'') + ' id=&quot;' + section.id + '&quot;&gt;' +</td></tr><tr><td class="line">813</td><td class="hits"></td><td class="source">      '&lt;h3&gt;' + t(section.label) + '&lt;/h3&gt;' +</td></tr><tr><td class="line">814</td><td class="hits"></td><td class="source">      self.render_fields(section, values) +</td></tr><tr><td class="line">815</td><td class="hits"></td><td class="source">      '&lt;/section&gt;'</td></tr><tr><td class="line">816</td><td class="hits"></td><td class="source">    );</td></tr><tr><td class="line">817</td><td class="hits"></td><td class="source">  });</td></tr><tr class="miss"><td class="line">818</td><td class="hits">0</td><td class="source">  return sectionOutput;</td></tr><tr><td class="line">819</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">820</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">821</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">822</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">823</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">824</td><td class="hits"></td><td class="source"> * Render the buttons on a form</td></tr><tr><td class="line">825</td><td class="hits"></td><td class="source"> * @param buttons</td></tr><tr><td class="line">826</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">827</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">828</td><td class="hits">1</td><td class="source">me.render_buttons = function(buttons) {</td></tr><tr><td class="line">829</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">830</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr class="miss"><td class="line">831</td><td class="hits">0</td><td class="source">  var buttonsOutput = '&lt;div class=&quot;actions&quot;&gt;';</td></tr><tr><td class="line">832</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">833</td><td class="hits">0</td><td class="source">  buttons.forEach(function(field) {</td></tr><tr class="miss"><td class="line">834</td><td class="hits">0</td><td class="source">    buttonsOutput += self.elementTypes[field.tag || field.type].render(field);</td></tr><tr><td class="line">835</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">836</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">837</td><td class="hits">0</td><td class="source">  buttonsOutput += '&lt;/div&gt;';</td></tr><tr><td class="line">838</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">839</td><td class="hits">0</td><td class="source">  return buttonsOutput;</td></tr><tr><td class="line">840</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">841</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">842</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">843</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">844</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">845</td><td class="hits"></td><td class="source"> * Render the fields on a form</td></tr><tr><td class="line">846</td><td class="hits"></td><td class="source"> * @param fields</td></tr><tr><td class="line">847</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">848</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">849</td><td class="hits">1</td><td class="source">me.render_fields = function(fieldContainer, values) {</td></tr><tr><td class="line">850</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">851</td><td class="hits">0</td><td class="source">  var fields = fieldContainer.fields || fieldContainer.children;</td></tr><tr class="miss"><td class="line">852</td><td class="hits">0</td><td class="source">  var self = this;</td></tr><tr class="miss"><td class="line">853</td><td class="hits">0</td><td class="source">  var fieldOutput = '';</td></tr><tr><td class="line">854</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">855</td><td class="hits">0</td><td class="source">  if(!fields) {</td></tr><tr class="miss"><td class="line">856</td><td class="hits">0</td><td class="source">    return '';</td></tr><tr><td class="line">857</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">858</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">859</td><td class="hits">0</td><td class="source">  fields.forEach( function(field) {</td></tr><tr><td class="line">860</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">861</td><td class="hits">0</td><td class="source">    var value = '';</td></tr><tr class="miss"><td class="line">862</td><td class="hits">0</td><td class="source">    var fieldName = field.name;</td></tr><tr><td class="line">863</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">864</td><td class="hits"></td><td class="source">    // If we have a field name, lookup the value</td></tr><tr class="miss"><td class="line">865</td><td class="hits">0</td><td class="source">    if(fieldName) {</td></tr><tr class="miss"><td class="line">866</td><td class="hits">0</td><td class="source">      value = getValueForField(fieldName, values);</td></tr><tr><td class="line">867</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">868</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">869</td><td class="hits"></td><td class="source">    // if the 'field' is really just a container, pass the values on down</td></tr><tr><td class="line">870</td><td class="hits"></td><td class="source">    // todo: consider adding a property 'isContainer'</td></tr><tr class="miss"><td class="line">871</td><td class="hits">0</td><td class="source">    if(field.type == 'section' || field.type == 'fieldset'){</td></tr><tr class="miss"><td class="line">872</td><td class="hits">0</td><td class="source">      value = values;</td></tr><tr><td class="line">873</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">874</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">875</td><td class="hits"></td><td class="source">    // field.tag was introduced to allow for &lt;button type=&quot;submit&quot;&gt; (without tag:button, that would be &lt;input type=&quot;submit&quot;&gt;)</td></tr><tr class="miss"><td class="line">876</td><td class="hits">0</td><td class="source">    if(self.elementTypes[field.tag || field.type]){</td></tr><tr class="miss"><td class="line">877</td><td class="hits">0</td><td class="source">      fieldOutput += self.elementTypes[field.tag || field.type].render(field, value, fieldContainer.tabs);  //self.render_field(field, value);</td></tr><tr><td class="line">878</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">879</td><td class="hits">0</td><td class="source">      calipso.warn('No renderer for ', field);</td></tr><tr><td class="line">880</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">881</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">882</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">883</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">884</td><td class="hits">0</td><td class="source">  return fieldOutput;</td></tr><tr><td class="line">885</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">886</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">887</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">888</td><td class="hits"></td><td class="source"> * Get the value for a form field from the values object</td></tr><tr><td class="line">889</td><td class="hits"></td><td class="source"> * @param from</td></tr><tr><td class="line">890</td><td class="hits"></td><td class="source"> * @param to</td></tr><tr><td class="line">891</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">892</td><td class="hits">1</td><td class="source">function getValueForField(field, values) {</td></tr><tr><td class="line">893</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">894</td><td class="hits">0</td><td class="source">  if(!values) return '';</td></tr><tr><td class="line">895</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">896</td><td class="hits"></td><td class="source">  // First of all, split the field name into keys</td></tr><tr class="miss"><td class="line">897</td><td class="hits">0</td><td class="source">  var path = []</td></tr><tr class="miss"><td class="line">898</td><td class="hits">0</td><td class="source">  if(field.match(/.*\]$/)) {</td></tr><tr class="miss"><td class="line">899</td><td class="hits">0</td><td class="source">    path = field.replace(/\]/g,&quot;&quot;).split(&quot;[&quot;);</td></tr><tr><td class="line">900</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">901</td><td class="hits">0</td><td class="source">    path = field.split(':');</td></tr><tr><td class="line">902</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">903</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">904</td><td class="hits">0</td><td class="source">  while (path.length &gt; 0) {</td></tr><tr><td class="line">905</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">906</td><td class="hits">0</td><td class="source">    key = path.shift();</td></tr><tr><td class="line">907</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">908</td><td class="hits">0</td><td class="source">    if (!(values &amp;&amp; key in values)) {</td></tr><tr class="miss"><td class="line">909</td><td class="hits">0</td><td class="source">      if(values &amp;&amp; (typeof values.get === &quot;function&quot;)) {</td></tr><tr class="miss"><td class="line">910</td><td class="hits">0</td><td class="source">        values = values.get(key);</td></tr><tr><td class="line">911</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">912</td><td class="hits">0</td><td class="source">        if(values &amp;&amp; values[field]) {</td></tr><tr class="miss"><td class="line">913</td><td class="hits">0</td><td class="source">          return values[field];</td></tr><tr><td class="line">914</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">915</td><td class="hits">0</td><td class="source">          return '';</td></tr><tr><td class="line">916</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">917</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">918</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">919</td><td class="hits">0</td><td class="source">      values = values[key];</td></tr><tr><td class="line">920</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">921</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">922</td><td class="hits">0</td><td class="source">    if (path.length === 0) {</td></tr><tr class="miss"><td class="line">923</td><td class="hits">0</td><td class="source">      return (values || '');</td></tr><tr><td class="line">924</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">925</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">926</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">927</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">928</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">929</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">930</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">931</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">932</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">933</td><td class="hits"></td><td class="source"> * Get the value for a form field from the values object</td></tr><tr><td class="line">934</td><td class="hits"></td><td class="source"> * @param from</td></tr><tr><td class="line">935</td><td class="hits"></td><td class="source"> * @param to</td></tr><tr><td class="line">936</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">937</td><td class="hits">1</td><td class="source">function setValueForField(field, values, value) {</td></tr><tr><td class="line">938</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">939</td><td class="hits">0</td><td class="source">  if(!values) return '';</td></tr><tr><td class="line">940</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">941</td><td class="hits"></td><td class="source">  // First of all, split the field name into keys</td></tr><tr class="miss"><td class="line">942</td><td class="hits">0</td><td class="source">  var path = []</td></tr><tr class="miss"><td class="line">943</td><td class="hits">0</td><td class="source">  if(field.match(/.*\]$/)) {</td></tr><tr class="miss"><td class="line">944</td><td class="hits">0</td><td class="source">    path = field.replace(/\]/g,&quot;&quot;).split(&quot;[&quot;);</td></tr><tr><td class="line">945</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">946</td><td class="hits">0</td><td class="source">    path = [field];</td></tr><tr><td class="line">947</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">948</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">949</td><td class="hits"></td><td class="source">  //</td></tr><tr><td class="line">950</td><td class="hits"></td><td class="source">  // Scope into the object to get the appropriate nested context</td></tr><tr><td class="line">951</td><td class="hits"></td><td class="source">  //</td></tr><tr class="miss"><td class="line">952</td><td class="hits">0</td><td class="source">  while (path.length &gt; 1) {</td></tr><tr class="miss"><td class="line">953</td><td class="hits">0</td><td class="source">    key = path.shift();</td></tr><tr class="miss"><td class="line">954</td><td class="hits">0</td><td class="source">    if (!values[key] || typeof values[key] !== 'object') {</td></tr><tr class="miss"><td class="line">955</td><td class="hits">0</td><td class="source">      values[key] = {};</td></tr><tr><td class="line">956</td><td class="hits"></td><td class="source">    }    </td></tr><tr class="miss"><td class="line">957</td><td class="hits">0</td><td class="source">    values = values[key];</td></tr><tr><td class="line">958</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">959</td><td class="hits"></td><td class="source">  </td></tr><tr><td class="line">960</td><td class="hits"></td><td class="source">  // Set the specified value in the nested JSON structure</td></tr><tr class="miss"><td class="line">961</td><td class="hits">0</td><td class="source">  key = path.shift();</td></tr><tr class="miss"><td class="line">962</td><td class="hits">0</td><td class="source">  values[key] = value;</td></tr><tr class="miss"><td class="line">963</td><td class="hits">0</td><td class="source">  return true;</td></tr><tr><td class="line">964</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">965</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">966</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">967</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">968</td><td class="hits"></td><td class="source"> * Recursive copy of object</td></tr><tr><td class="line">969</td><td class="hits"></td><td class="source"> * @param from</td></tr><tr><td class="line">970</td><td class="hits"></td><td class="source"> * @param to</td></tr><tr><td class="line">971</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">972</td><td class="hits">1</td><td class="source">function copyFormToObject(field, value, target) {</td></tr><tr><td class="line">973</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">974</td><td class="hits"></td><td class="source">  // First of all, split the field name into keys</td></tr><tr class="miss"><td class="line">975</td><td class="hits">0</td><td class="source">  var path = []</td></tr><tr class="miss"><td class="line">976</td><td class="hits">0</td><td class="source">  if(field.match(/.*\]$/)) {</td></tr><tr><td class="line">977</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">978</td><td class="hits">0</td><td class="source">    path = field.replace(/\]/g,&quot;&quot;).split(&quot;[&quot;);</td></tr><tr><td class="line">979</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">980</td><td class="hits"></td><td class="source">    // Now, copy over</td></tr><tr class="miss"><td class="line">981</td><td class="hits">0</td><td class="source">    while (path.length &gt; 1) {</td></tr><tr class="miss"><td class="line">982</td><td class="hits">0</td><td class="source">      key = path.shift();</td></tr><tr class="miss"><td class="line">983</td><td class="hits">0</td><td class="source">      if (!target[key]) {</td></tr><tr class="miss"><td class="line">984</td><td class="hits">0</td><td class="source">        target[key] = {};</td></tr><tr><td class="line">985</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">986</td><td class="hits">0</td><td class="source">      target = target[key];</td></tr><tr><td class="line">987</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">988</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">989</td><td class="hits"></td><td class="source">    // Shift one more time and set the value</td></tr><tr class="miss"><td class="line">990</td><td class="hits">0</td><td class="source">    key = path.shift();</td></tr><tr class="miss"><td class="line">991</td><td class="hits">0</td><td class="source">    target[key] = value;</td></tr><tr><td class="line">992</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">993</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">994</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">995</td><td class="hits"></td><td class="source">    // We are probably an nconf form, hence just copy over</td></tr><tr class="miss"><td class="line">996</td><td class="hits">0</td><td class="source">    target[field] = value;</td></tr><tr><td class="line">997</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">998</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">999</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1000</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1001</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1002</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1003</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1004</td><td class="hits"></td><td class="source"> * Process a field / section array from a contentType</td></tr><tr><td class="line">1005</td><td class="hits"></td><td class="source"> * And modify the form</td></tr><tr><td class="line">1006</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1007</td><td class="hits">1</td><td class="source">me.processFields = function(form, fields) {</td></tr><tr><td class="line">1008</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1009</td><td class="hits"></td><td class="source">  // Process fields</td></tr><tr class="miss"><td class="line">1010</td><td class="hits">0</td><td class="source">  if(fields.fields) {</td></tr><tr class="miss"><td class="line">1011</td><td class="hits">0</td><td class="source">    processFieldArray(form,fields.fields);</td></tr><tr><td class="line">1012</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1013</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1014</td><td class="hits">0</td><td class="source">  if(fields.sections) {</td></tr><tr class="miss"><td class="line">1015</td><td class="hits">0</td><td class="source">    fields.sections.forEach(function(section,key) {</td></tr><tr><td class="line">1016</td><td class="hits"></td><td class="source">      // Process fields</td></tr><tr class="miss"><td class="line">1017</td><td class="hits">0</td><td class="source">      if(section.label) {</td></tr><tr class="miss"><td class="line">1018</td><td class="hits">0</td><td class="source">        form.sections.push(section);</td></tr><tr><td class="line">1019</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">1020</td><td class="hits"></td><td class="source">      // Remove it</td></tr><tr class="miss"><td class="line">1021</td><td class="hits">0</td><td class="source">      if(section.hide) {</td></tr><tr class="miss"><td class="line">1022</td><td class="hits">0</td><td class="source">        form = removeSection(form,section.id);</td></tr><tr><td class="line">1023</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">1024</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">1025</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1026</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1027</td><td class="hits">0</td><td class="source">  return form;</td></tr><tr><td class="line">1028</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1029</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">1030</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1031</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1032</td><td class="hits"></td><td class="source">// Helper function to process fields</td></tr><tr class="hit"><td class="line">1033</td><td class="hits">1</td><td class="source">function processFieldArray(form, fields) {</td></tr><tr><td class="line">1034</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1035</td><td class="hits">0</td><td class="source">  fields.forEach(function(field, key) {</td></tr><tr><td class="line">1036</td><td class="hits"></td><td class="source">    // Add it</td></tr><tr class="miss"><td class="line">1037</td><td class="hits">0</td><td class="source">    if(field.type) {</td></tr><tr class="miss"><td class="line">1038</td><td class="hits">0</td><td class="source">      form.fields.push(field);</td></tr><tr><td class="line">1039</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1040</td><td class="hits"></td><td class="source">    // Remove it</td></tr><tr class="miss"><td class="line">1041</td><td class="hits">0</td><td class="source">    if(field.hide) {</td></tr><tr class="miss"><td class="line">1042</td><td class="hits">0</td><td class="source">      form = removeField(form, field.name);</td></tr><tr><td class="line">1043</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1044</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">1045</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1046</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1047</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1048</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1049</td><td class="hits"></td><td class="source"> * Remove a field from a form (any section)</td></tr><tr><td class="line">1050</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1051</td><td class="hits">1</td><td class="source">function removeField(form, fieldName) {</td></tr><tr><td class="line">1052</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1053</td><td class="hits"></td><td class="source">  // Scan sections</td></tr><tr class="miss"><td class="line">1054</td><td class="hits">0</td><td class="source">  form.sections.forEach(function(section, key) {</td></tr><tr class="miss"><td class="line">1055</td><td class="hits">0</td><td class="source">    scanFields(section.fields, fieldName);</td></tr><tr><td class="line">1056</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">1057</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1058</td><td class="hits"></td><td class="source">  // Form fields</td></tr><tr class="miss"><td class="line">1059</td><td class="hits">0</td><td class="source">  scanFields(form.fields, fieldName);</td></tr><tr><td class="line">1060</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1061</td><td class="hits">0</td><td class="source">  return form;</td></tr><tr><td class="line">1062</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1063</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1064</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1065</td><td class="hits"></td><td class="source">// Helper function for removeField</td></tr><tr class="hit"><td class="line">1066</td><td class="hits">1</td><td class="source">function scanFields(fieldArray, fieldName) {</td></tr><tr class="miss"><td class="line">1067</td><td class="hits">0</td><td class="source">  fieldArray.forEach(function(field, key) {</td></tr><tr class="miss"><td class="line">1068</td><td class="hits">0</td><td class="source">    if(field.name === fieldName) {</td></tr><tr class="miss"><td class="line">1069</td><td class="hits">0</td><td class="source">      fieldArray = fieldArray.splice(key, 1);</td></tr><tr><td class="line">1070</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1071</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">1072</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1073</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1074</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1075</td><td class="hits"></td><td class="source"> * Remove a section from a form</td></tr><tr><td class="line">1076</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1077</td><td class="hits">1</td><td class="source">function removeSection(form, sectionId) {</td></tr><tr><td class="line">1078</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1079</td><td class="hits"></td><td class="source">  // Scan sections</td></tr><tr class="miss"><td class="line">1080</td><td class="hits">0</td><td class="source">  form.sections.forEach(function(section,key) {</td></tr><tr class="miss"><td class="line">1081</td><td class="hits">0</td><td class="source">    if(section.id === sectionId) {</td></tr><tr class="miss"><td class="line">1082</td><td class="hits">0</td><td class="source">      form.sections.splice(key,1);</td></tr><tr><td class="line">1083</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1084</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">1085</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1086</td><td class="hits">0</td><td class="source">  return form;</td></tr><tr><td class="line">1087</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1088</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1089</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1090</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1091</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1092</td><td class="hits"></td><td class="source"> * Simple object mapper, used to copy over form values to schemas</td></tr><tr><td class="line">1093</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1094</td><td class="hits">1</td><td class="source">me.mapFields = function(fields, record) {</td></tr><tr><td class="line">1095</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1096</td><td class="hits">0</td><td class="source">  var props = Object.getOwnPropertyNames(fields);</td></tr><tr class="miss"><td class="line">1097</td><td class="hits">0</td><td class="source">  props.forEach( function(name) {</td></tr><tr><td class="line">1098</td><td class="hits"></td><td class="source">    // If not private (e.g. _id), then copy</td></tr><tr class="miss"><td class="line">1099</td><td class="hits">0</td><td class="source">    if(!name.match(/^_.*/)) {</td></tr><tr class="miss"><td class="line">1100</td><td class="hits">0</td><td class="source">      record.set(name, fields[name]);</td></tr><tr><td class="line">1101</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1102</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">1103</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1104</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">1105</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1106</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1107</td><td class="hits"></td><td class="source"> * Process the values submitted by a form and return a JSON</td></tr><tr><td class="line">1108</td><td class="hits"></td><td class="source"> * object representation (makes it simpler to then process a form submission</td></tr><tr><td class="line">1109</td><td class="hits"></td><td class="source"> * from within a module.</td></tr><tr><td class="line">1110</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1111</td><td class="hits">1</td><td class="source">me.process = function(req, next) {</td></tr><tr><td class="line">1112</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1113</td><td class="hits"></td><td class="source">  // Fix until all modules refactored to use formData</td></tr><tr class="miss"><td class="line">1114</td><td class="hits">0</td><td class="source">  if(req.formProcessed) {</td></tr><tr><td class="line">1115</td><td class="hits"></td><td class="source">    </td></tr><tr class="miss"><td class="line">1116</td><td class="hits">0</td><td class="source">    next(req.formData, req.uploadedFiles);</td></tr><tr class="miss"><td class="line">1117</td><td class="hits">0</td><td class="source">    return;</td></tr><tr><td class="line">1118</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1119</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">1120</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1121</td><td class="hits"></td><td class="source">    // Data parsed based on original form structure</td></tr><tr class="miss"><td class="line">1122</td><td class="hits">0</td><td class="source">    processFormData(req, function(err, formData) {</td></tr><tr><td class="line">1123</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1124</td><td class="hits">0</td><td class="source">      if(err) calipso.error(err);</td></tr><tr><td class="line">1125</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1126</td><td class="hits">0</td><td class="source">      req.formData = formData;</td></tr><tr class="miss"><td class="line">1127</td><td class="hits">0</td><td class="source">      req.formProcessed = true;</td></tr><tr><td class="line">1128</td><td class="hits"></td><td class="source">      </td></tr><tr class="miss"><td class="line">1129</td><td class="hits">0</td><td class="source">      return next(req.formData, req.files);</td></tr><tr><td class="line">1130</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1131</td><td class="hits"></td><td class="source">    }); </td></tr><tr><td class="line">1132</td><td class="hits"></td><td class="source">    </td></tr><tr><td class="line">1133</td><td class="hits"></td><td class="source">  } </td></tr><tr><td class="line">1134</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1135</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">1136</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1137</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1138</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1139</td><td class="hits"></td><td class="source"> * This process the incoming form, if the form exists in session then use that</td></tr><tr><td class="line">1140</td><td class="hits"></td><td class="source"> * to validate and convert incoming data against.</td></tr><tr><td class="line">1141</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1142</td><td class="hits">1</td><td class="source">function processFormData(req, next) {</td></tr><tr><td class="line">1143</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1144</td><td class="hits">0</td><td class="source">  if(calipso.lib._.keys(req.body).length === 0) {</td></tr><tr><td class="line">1145</td><td class="hits"></td><td class="source">    // No data</td></tr><tr class="miss"><td class="line">1146</td><td class="hits">0</td><td class="source">    return next();</td></tr><tr><td class="line">1147</td><td class="hits"></td><td class="source">  } </td></tr><tr><td class="line">1148</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1149</td><td class="hits"></td><td class="source">  // Get the form id and then remove from the response  </td></tr><tr class="miss"><td class="line">1150</td><td class="hits">0</td><td class="source">  var formId = req.body.form ? req.body.form.id : '';</td></tr><tr class="miss"><td class="line">1151</td><td class="hits">0</td><td class="source">  delete req.body.form;</td></tr><tr><td class="line">1152</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1153</td><td class="hits"></td><td class="source">  // Get the form and then delete the form from the user session to clean up</td></tr><tr class="miss"><td class="line">1154</td><td class="hits">0</td><td class="source">  var form = req.session.forms ? req.session.forms[formId] : null;</td></tr><tr class="miss"><td class="line">1155</td><td class="hits">0</td><td class="source">  var formData = req.body;</td></tr><tr><td class="line">1156</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1157</td><td class="hits">0</td><td class="source">  if(formId &amp;&amp; form) {</td></tr><tr><td class="line">1158</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1159</td><td class="hits">0</td><td class="source">    processSectionData(form, formData, function(err, formData) {</td></tr><tr><td class="line">1160</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1161</td><td class="hits">0</td><td class="source">      delete req.session.forms[formId];</td></tr><tr><td class="line">1162</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1163</td><td class="hits">0</td><td class="source">      req.session.save(function(err) {</td></tr><tr class="miss"><td class="line">1164</td><td class="hits">0</td><td class="source">        if(err) calipso.error(err.message);</td></tr><tr><td class="line">1165</td><td class="hits"></td><td class="source">      }); // Doesn't matter that this is async, can happen in background</td></tr><tr><td class="line">1166</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1167</td><td class="hits">0</td><td class="source">      return next(err, formData);</td></tr><tr><td class="line">1168</td><td class="hits"></td><td class="source">          </td></tr><tr><td class="line">1169</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">1170</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1171</td><td class="hits"></td><td class="source">  } else {   </td></tr><tr><td class="line">1172</td><td class="hits"></td><td class="source">   </td></tr><tr><td class="line">1173</td><td class="hits"></td><td class="source">    // No form in session, do not process</td></tr><tr class="miss"><td class="line">1174</td><td class="hits">0</td><td class="source">    next(null, formData);</td></tr><tr><td class="line">1175</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1176</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1177</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1178</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1179</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1180</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1181</td><td class="hits"></td><td class="source"> * Process form sections and fields.</td></tr><tr><td class="line">1182</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1183</td><td class="hits">1</td><td class="source">function processSectionData(form, formData, next) {</td></tr><tr><td class="line">1184</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1185</td><td class="hits"></td><td class="source">  // Create a single array of all the form and section fields</td></tr><tr class="miss"><td class="line">1186</td><td class="hits">0</td><td class="source">  var fields = [];</td></tr><tr><td class="line">1187</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1188</td><td class="hits">0</td><td class="source">  if(form.sections) {</td></tr><tr class="miss"><td class="line">1189</td><td class="hits">0</td><td class="source">    form.sections.forEach(function(section) {</td></tr><tr class="miss"><td class="line">1190</td><td class="hits">0</td><td class="source">      fields.push(section.fields);</td></tr><tr><td class="line">1191</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">1192</td><td class="hits"></td><td class="source">  }</td></tr><tr class="miss"><td class="line">1193</td><td class="hits">0</td><td class="source">  if(form.fields) {</td></tr><tr class="miss"><td class="line">1194</td><td class="hits">0</td><td class="source">    fields.push(form.fields);</td></tr><tr><td class="line">1195</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1196</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1197</td><td class="hits">0</td><td class="source">  calipso.lib.async.map(fields, function(section, cb) {</td></tr><tr class="miss"><td class="line">1198</td><td class="hits">0</td><td class="source">    processFieldData(section, formData, cb);</td></tr><tr><td class="line">1199</td><td class="hits"></td><td class="source">  }, function(err, result) {</td></tr><tr class="miss"><td class="line">1200</td><td class="hits">0</td><td class="source">      next(err, formData);</td></tr><tr><td class="line">1201</td><td class="hits"></td><td class="source">  })</td></tr><tr><td class="line">1202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1203</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1204</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1205</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1206</td><td class="hits"></td><td class="source"> * Process form fields.</td></tr><tr><td class="line">1207</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1208</td><td class="hits">1</td><td class="source">function processFieldData(fields, formData, next) {</td></tr><tr><td class="line">1209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1210</td><td class="hits"></td><td class="source">  // First create an array of all the fields (and field sets) to allow us to do an async.map</td></tr><tr class="miss"><td class="line">1211</td><td class="hits">0</td><td class="source">  var formFields = [];</td></tr><tr><td class="line">1212</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1213</td><td class="hits">0</td><td class="source">  for(var fieldName in fields) {</td></tr><tr><td class="line">1214</td><td class="hits"></td><td class="source">    // It is a section that contains fields</td></tr><tr class="miss"><td class="line">1215</td><td class="hits">0</td><td class="source">    var field = fields[fieldName];</td></tr><tr class="miss"><td class="line">1216</td><td class="hits">0</td><td class="source">    if(field.fields) {</td></tr><tr><td class="line">1217</td><td class="hits"></td><td class="source">      // This is a field set</td></tr><tr class="miss"><td class="line">1218</td><td class="hits">0</td><td class="source">      for(var subFieldName in field.fields) {</td></tr><tr class="miss"><td class="line">1219</td><td class="hits">0</td><td class="source">        formFields.push(field.fields[subFieldName]);</td></tr><tr><td class="line">1220</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">1221</td><td class="hits"></td><td class="source">    } else {        </td></tr><tr><td class="line">1222</td><td class="hits"></td><td class="source">      // Just push the field</td></tr><tr class="miss"><td class="line">1223</td><td class="hits">0</td><td class="source">      formFields.push(field)</td></tr><tr><td class="line">1224</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1225</td><td class="hits"></td><td class="source">  }  </td></tr><tr><td class="line">1226</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1227</td><td class="hits">0</td><td class="source">  var iteratorFn = function(field, cb) {</td></tr><tr><td class="line">1228</td><td class="hits"></td><td class="source">    </td></tr><tr class="miss"><td class="line">1229</td><td class="hits">0</td><td class="source">    var value = getValueForField(field.name, formData);</td></tr><tr class="miss"><td class="line">1230</td><td class="hits">0</td><td class="source">    processFieldValue(field, value, function(err, processedValue) {</td></tr><tr class="miss"><td class="line">1231</td><td class="hits">0</td><td class="source">      if(value !== processedValue) setValueForField(field.name, formData, processedValue);</td></tr><tr class="miss"><td class="line">1232</td><td class="hits">0</td><td class="source">      cb(err, true);    </td></tr><tr><td class="line">1233</td><td class="hits"></td><td class="source">    });                    </td></tr><tr><td class="line">1234</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1235</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1236</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1237</td><td class="hits">0</td><td class="source">  calipso.lib.async.map(formFields, iteratorFn, next);</td></tr><tr><td class="line">1238</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1239</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1240</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1241</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1242</td><td class="hits"></td><td class="source"> * Process submitted values against the original form.</td></tr><tr><td class="line">1243</td><td class="hits"></td><td class="source"> * TODO: This is where we would bolt on any validation.</td></tr><tr><td class="line">1244</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1245</td><td class="hits">1</td><td class="source">function processFieldValue(field, value, next) {</td></tr><tr><td class="line">1246</td><td class="hits"></td><td class="source">  </td></tr><tr><td class="line">1247</td><td class="hits"></td><td class="source">  // Process each field</td></tr><tr class="miss"><td class="line">1248</td><td class="hits">0</td><td class="source">  if(field.type === 'checkbox') {</td></tr><tr><td class="line">1249</td><td class="hits"></td><td class="source">    </td></tr><tr class="miss"><td class="line">1250</td><td class="hits">0</td><td class="source">    if(typeof value === 'object') {</td></tr><tr><td class="line">1251</td><td class="hits"></td><td class="source">      // The value has come in as ['off','on'] or [false,true]</td></tr><tr><td class="line">1252</td><td class="hits"></td><td class="source">      // So we always take the last value</td></tr><tr class="miss"><td class="line">1253</td><td class="hits">0</td><td class="source">      value = value[value.length - 1];</td></tr><tr><td class="line">1254</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1255</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1256</td><td class="hits"></td><td class="source">    // Deal with on off</td></tr><tr class="miss"><td class="line">1257</td><td class="hits">0</td><td class="source">    if(value === 'on') value = true;</td></tr><tr class="miss"><td class="line">1258</td><td class="hits">0</td><td class="source">    if(value === 'off') value = false;</td></tr><tr><td class="line">1259</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1260</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1261</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1262</td><td class="hits">0</td><td class="source">  if(field.type === 'select') {</td></tr><tr><td class="line">1263</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1264</td><td class="hits"></td><td class="source">    // Deal with Yes / No &gt; Boolean</td></tr><tr class="miss"><td class="line">1265</td><td class="hits">0</td><td class="source">    if(value === 'Yes') value = true;</td></tr><tr class="miss"><td class="line">1266</td><td class="hits">0</td><td class="source">    if(value === 'No') value = false;</td></tr><tr><td class="line">1267</td><td class="hits"></td><td class="source">    </td></tr><tr><td class="line">1268</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1269</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1270</td><td class="hits">0</td><td class="source">  if(field.type === 'datetime') {</td></tr><tr><td class="line">1271</td><td class="hits"></td><td class="source">    </td></tr><tr class="miss"><td class="line">1272</td><td class="hits">0</td><td class="source">     if(value.hasOwnProperty('date') &amp;&amp; value.hasOwnProperty('time')) {</td></tr><tr class="miss"><td class="line">1273</td><td class="hits">0</td><td class="source">      value = new Date(</td></tr><tr><td class="line">1274</td><td class="hits"></td><td class="source">        value.date + &quot; &quot; + value.time</td></tr><tr><td class="line">1275</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">1276</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1277</td><td class="hits"></td><td class="source">  </td></tr><tr class="miss"><td class="line">1278</td><td class="hits">0</td><td class="source">    if(value.hasOwnProperty('date') &amp;&amp; value.hasOwnProperty('hours')) {</td></tr><tr class="miss"><td class="line">1279</td><td class="hits">0</td><td class="source">      value = new Date(</td></tr><tr><td class="line">1280</td><td class="hits"></td><td class="source">        value.date + &quot; &quot; + value.hours + &quot;:&quot; + value.minutes + &quot;:00&quot;</td></tr><tr><td class="line">1281</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">1282</td><td class="hits"></td><td class="source">    } </td></tr><tr><td class="line">1283</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1284</td><td class="hits">0</td><td class="source">    if(value.hasOwnProperty('year') &amp;&amp; value.hasOwnProperty('hours')) {</td></tr><tr><td class="line">1285</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1286</td><td class="hits">0</td><td class="source">      var now = new Date();</td></tr><tr><td class="line">1287</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1288</td><td class="hits">0</td><td class="source">      value = new Date(</td></tr><tr><td class="line">1289</td><td class="hits"></td><td class="source">        (value.year || now.getFullYear()),</td></tr><tr><td class="line">1290</td><td class="hits"></td><td class="source">        (value.month || now.getMonth()),</td></tr><tr><td class="line">1291</td><td class="hits"></td><td class="source">        (value.day || now.getDate()),</td></tr><tr><td class="line">1292</td><td class="hits"></td><td class="source">        (value.hours || now.getHours()),</td></tr><tr><td class="line">1293</td><td class="hits"></td><td class="source">        (value.minutes || now.getMinutes()),</td></tr><tr><td class="line">1294</td><td class="hits"></td><td class="source">        (value.seconds || now.getSeconds())</td></tr><tr><td class="line">1295</td><td class="hits"></td><td class="source">      );</td></tr><tr><td class="line">1296</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1297</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">1298</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1299</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">1300</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">1301</td><td class="hits">0</td><td class="source">  return next(null, value);</td></tr><tr><td class="line">1302</td><td class="hits"></td><td class="source">  </td></tr><tr><td class="line">1303</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">1304</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">1305</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">1306</td><td class="hits"></td><td class="source"> * Export an instance of our form object</td></tr><tr><td class="line">1307</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">1308</td><td class="hits">1</td><td class="source">module.exports = f;</td></tr></tbody></table></div><div class="file"><h2 id="core/Helpers.js">core/Helpers.js</h2><div id="stats" class="medium"><div class="percentage">65%</div><div class="sloc">69</div><div class="hits">45</div><div class="misses">24</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *  Dynamic helpers for insertion into the templating engine</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> *  They all need to take in a req,res pair, these are then</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *  interpreted during the request stack and passed into the</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> *  view engine (so for example 'request' is accessible).</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> * removes any trailing query string or hash values</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * @method stripUrlToConvert</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * @param url {string} The url to convert</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> * @return {String} Converted url, if applicable</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">1</td><td class="source">function stripUrlToConvert(url) {</td></tr><tr class="hit"><td class="line">21</td><td class="hits">8</td><td class="source">  var qs = url.search(/\?|#/);</td></tr><tr class="hit"><td class="line">22</td><td class="hits">8</td><td class="source">  if (qs &gt; -1) {</td></tr><tr class="miss"><td class="line">23</td><td class="hits">0</td><td class="source">    url = url.substring(0, qs);</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">25</td><td class="hits">8</td><td class="source">  return url;</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> * Exports</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">31</td><td class="hits">1</td><td class="source">exports = module.exports = {</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  // Attach view Helpers to the request</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  getDynamicHelpers: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">35</td><td class="hits">4</td><td class="source">    var self = this;</td></tr><tr class="hit"><td class="line">36</td><td class="hits">4</td><td class="source">    req.helpers = {};</td></tr><tr class="hit"><td class="line">37</td><td class="hits">4</td><td class="source">    for (var helper in self.helpers) {</td></tr><tr class="hit"><td class="line">38</td><td class="hits">80</td><td class="source">      req.helpers[helper] = self.helpers[helper](req, res, calipso);</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">  // Add a new helper (e.g. so modules can add them)</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">  addHelper: function(name, fn) {</td></tr><tr class="miss"><td class="line">44</td><td class="hits">0</td><td class="source">    var self = this;</td></tr><tr class="miss"><td class="line">45</td><td class="hits">0</td><td class="source">    self.helpers[name] = fn;</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">  helpers: {</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">     * Request shortcut</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">    request: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">53</td><td class="hits">4</td><td class="source">      return req;</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">     * Config shortcut</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">    config: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">60</td><td class="hits">4</td><td class="source">      return calipso.config;</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">     * Translation shortcut</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">    t: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">67</td><td class="hits">4</td><td class="source">      return req.t;</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">     * User shortcut</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">    user: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">74</td><td class="hits">4</td><td class="source">      return req.session &amp;&amp; req.session.user || {</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">        username: '',</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">        anonymous: true</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">     * Pretty date helper</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">    prettyDate: function(req, res, calipso) {</td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">85</td><td class="hits">4</td><td class="source">      var prettyFn = calipso.lib.prettyDate.prettyDate;</td></tr><tr class="hit"><td class="line">86</td><td class="hits">4</td><td class="source">      return prettyFn;</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">     * Hot date helper</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">    hotDate: function(req, res, calipso) {</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">95</td><td class="hits">4</td><td class="source">      var hotFn = calipso.lib.prettyDate.hotDate;</td></tr><tr class="hit"><td class="line">96</td><td class="hits">4</td><td class="source">      return hotFn;</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">     * Get block data not included preloaded in the theme configuration (in blockData)</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">    getBlock: function(req, res, calipso) {</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">105</td><td class="hits">4</td><td class="source">      return function(block, next) {</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">        // TODO : Allow block to be passed as a regex (e.g. to include all scripts.* blocks)</td></tr><tr class="hit"><td class="line">108</td><td class="hits">8</td><td class="source">        var output = &quot;&quot;;</td></tr><tr class="hit"><td class="line">109</td><td class="hits">8</td><td class="source">        res.renderedBlocks.get(block, function(err, blocks) {</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">111</td><td class="hits">8</td><td class="source">          blocks.forEach(function(content) {</td></tr><tr class="hit"><td class="line">112</td><td class="hits">1</td><td class="source">            output += content;</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">115</td><td class="hits">16</td><td class="source">          if (typeof next === 'function') next(null, output);</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">     * Get a menu html, synchronous</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">    getMenu: function(req, res, calipso) {</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">127</td><td class="hits">4</td><td class="source">      return function(menu, depth) {</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">        // Render menu</td></tr><tr class="hit"><td class="line">129</td><td class="hits">12</td><td class="source">        if (res.menu[menu]) {</td></tr><tr class="hit"><td class="line">130</td><td class="hits">12</td><td class="source">          var output = res.menu[menu].render(req, depth);</td></tr><tr class="hit"><td class="line">131</td><td class="hits">12</td><td class="source">          return output;</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">133</td><td class="hits">0</td><td class="source">          return 'Menu ' + menu + ' does not exist!';</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">     * Directly call an exposed module function (e.g. over ride routing rules and inject it anywhere)</td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source">    getModuleFn: function(req, res, calipso) {</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">144</td><td class="hits">4</td><td class="source">      return function(req, moduleFunction, options, next) {</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source">        // Call an exposed module function</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">        // e.g. user.loginForm(req, res, template, block, next)</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">        // First see if function exists</td></tr><tr class="miss"><td class="line">149</td><td class="hits">0</td><td class="source">        var moduleName = moduleFunction.split(&quot;.&quot;)[0];</td></tr><tr class="miss"><td class="line">150</td><td class="hits">0</td><td class="source">        var functionName = moduleFunction.split(&quot;.&quot;)[1];</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">152</td><td class="hits">0</td><td class="source">        if (calipso.modules[moduleName] &amp;&amp; calipso.modules[moduleName].enabled &amp;&amp; calipso.modules[moduleName].fn[functionName]) {</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">154</td><td class="hits">0</td><td class="source">          var fn = calipso.modules[moduleName].fn[functionName];</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">          // Get the template</td></tr><tr class="miss"><td class="line">157</td><td class="hits">0</td><td class="source">          var template;</td></tr><tr class="miss"><td class="line">158</td><td class="hits">0</td><td class="source">          if (options.template &amp;&amp; calipso.modules[moduleName].templates[options.template]) {</td></tr><tr class="miss"><td class="line">159</td><td class="hits">0</td><td class="source">            template = calipso.modules[moduleName].templates[options.template];</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source">          // Call the fn</td></tr><tr class="miss"><td class="line">163</td><td class="hits">0</td><td class="source">          try {</td></tr><tr class="miss"><td class="line">164</td><td class="hits">0</td><td class="source">            fn(req, res, template, null, next);</td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source">          } catch (ex) {</td></tr><tr class="miss"><td class="line">166</td><td class="hits">0</td><td class="source">            next(ex);</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">170</td><td class="hits">0</td><td class="source">          next(null, &quot;&lt;div class='error'&gt;Function &quot; + moduleFunction + &quot; requested via getModuleFn does not exist or module is not enabled.&lt;/div&gt;&quot;);</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source">     * Retrieves the params parsed during module routing</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source">    getParams: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">181</td><td class="hits">4</td><td class="source">      return function() {</td></tr><tr class="miss"><td class="line">182</td><td class="hits">0</td><td class="source">        return res.params;</td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source">     * Constructs individual classes based on the url request</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source">    getPageClasses: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">190</td><td class="hits">4</td><td class="source">      var url = stripUrlToConvert(req.url);</td></tr><tr class="hit"><td class="line">191</td><td class="hits">4</td><td class="source">      return url.split('/').join(' ');</td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">     * Constructs a single id based on the url request</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">    getPageId: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">198</td><td class="hits">4</td><td class="source">      var url = stripUrlToConvert(req.url),</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source">        urlFrags = url.split('/');</td></tr><tr class="hit"><td class="line">200</td><td class="hits">4</td><td class="source">      for (var i = 0, len = urlFrags.length; i &lt; len; i++) {</td></tr><tr class="hit"><td class="line">201</td><td class="hits">8</td><td class="source">        var frag = urlFrags[i];</td></tr><tr class="hit"><td class="line">202</td><td class="hits">8</td><td class="source">        if (frag === '') {</td></tr><tr class="hit"><td class="line">203</td><td class="hits">4</td><td class="source">          urlFrags.splice(i, 1);</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">      }</td></tr><tr class="hit"><td class="line">206</td><td class="hits">4</td><td class="source">      return urlFrags.join('-');</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">    addScript: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">211</td><td class="hits">4</td><td class="source">      return function(options) {</td></tr><tr class="miss"><td class="line">212</td><td class="hits">0</td><td class="source">        res.client.addScript(options);</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">    getScripts: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">217</td><td class="hits">4</td><td class="source">      return function(next) {</td></tr><tr class="miss"><td class="line">218</td><td class="hits">0</td><td class="source">        res.client.listScripts(next);</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source">    addStyle: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">224</td><td class="hits">4</td><td class="source">      return function(options) {</td></tr><tr class="miss"><td class="line">225</td><td class="hits">0</td><td class="source">        res.client.addStyle(options);</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">    getStyles: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">230</td><td class="hits">4</td><td class="source">      return function(next) {</td></tr><tr class="miss"><td class="line">231</td><td class="hits">0</td><td class="source">        res.client.listStyles(next);</td></tr><tr><td class="line">232</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source">     * Flash message helpers</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source">    flashMessages: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">239</td><td class="hits">4</td><td class="source">      return function() {</td></tr><tr class="miss"><td class="line">240</td><td class="hits">0</td><td class="source">        return req.flash();</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source">    /**</td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">     * HTML helpers - form (formApi), table, link (for now)</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source">     */</td></tr><tr><td class="line">247</td><td class="hits"></td><td class="source">    formApi: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">248</td><td class="hits">4</td><td class="source">      return function(form) {</td></tr><tr class="miss"><td class="line">249</td><td class="hits">0</td><td class="source">        return calipso.form.render(form);</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">    table: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">253</td><td class="hits">4</td><td class="source">      return function(table) {</td></tr><tr class="miss"><td class="line">254</td><td class="hits">0</td><td class="source">        return calipso.table.render(table);</td></tr><tr><td class="line">255</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source">    },</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">    link: function(req, res, calipso) {</td></tr><tr class="hit"><td class="line">258</td><td class="hits">4</td><td class="source">      return function(link) {</td></tr><tr class="miss"><td class="line">259</td><td class="hits">0</td><td class="source">        return calipso.link.render(link);</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/Lib.js">core/Lib.js</h2><div id="stats" class="high"><div class="percentage">100%</div><div class="sloc">2</div><div class="hits">2</div><div class="misses">0</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Imports</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * This library is used to allow a single place to add new 3rd party libraries or utilities that </td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * are then automatically accessible via calipso.lib.library in any module.</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *  </td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">11</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/';</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">13</td><td class="hits">1</td><td class="source">module.exports = {</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">    fs: require('fs'),</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">    path: require('path'),</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">    express: require('express'),</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">    step: require('step'),</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">    util: require('util'),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">    mongoose: require('mongoose'),</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">    url: require('url'),</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">    ejs: require('ejs'),</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">    pager: require(rootpath + 'utils/pager'),</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">    prettyDate: require(rootpath + 'utils/prettyDate.js'),</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">    crypto: require(rootpath + 'utils/crypto.js'),</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">    connect: require('connect'),</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">    _: require('underscore'),</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">    async: require('async')</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/Link.js">core/Link.js</h2><div id="stats" class="medium"><div class="percentage">50%</div><div class="sloc">12</div><div class="hits">6</div><div class="misses">6</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Calipso Link Rendering Library</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * Loaded into calipso as a plugin, used to simplify rendering of links</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">12</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">  qs = require('qs');</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">// Global variable (in this context) for translation function</td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">var t;</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> * The default calipso link object, with default configuration values.</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> * Constructor</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">25</td><td class="hits">1</td><td class="source">function CalipsoLink() {</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">  //TODO Allow over-ride</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> * Export an instance of our link object</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">33</td><td class="hits">1</td><td class="source">module.exports = new CalipsoLink();</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> * Link Renderer, controls the overall creation of the tablle based on a form json object passed</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> * in as the first parameter.  The structure of this object is as follows:</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> *     link</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> *        id : Unique ID that will become the link ID.</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> *        title : Title to show (hover)</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> *        target : target window</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source"> *        label : label to show in link</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> *        cls : css class</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> *        url: the direct url to use, can be function (mandatory)</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> * @param item : the json object representing the form</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source"> * @param next : Callback when done, pass markup as return val.</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">51</td><td class="hits">1</td><td class="source">CalipsoLink.prototype.render = function(item) {</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">53</td><td class="hits">0</td><td class="source">  return (</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">  this.render_link(item));</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> * Render link</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source"> * @param link</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">64</td><td class="hits">1</td><td class="source">CalipsoLink.prototype.render_link = function(link) {</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">66</td><td class="hits">0</td><td class="source">  var url = &quot;&quot;;</td></tr><tr class="miss"><td class="line">67</td><td class="hits">0</td><td class="source">  if (typeof link.url === 'function') {</td></tr><tr class="miss"><td class="line">68</td><td class="hits">0</td><td class="source">    url = link.url(link);</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">70</td><td class="hits">0</td><td class="source">    url = link.url;</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">73</td><td class="hits">0</td><td class="source">  return ('&lt;a' + ' href=&quot;' + url + '&quot;' + (link.id ? ' id=' + link.id + '&quot;' : &quot;&quot;) + (link.target ? ' target=&quot;' + link.target + '&quot;' : &quot;&quot;) + (link.title ? ' title=&quot;' + link.title + '&quot;' : &quot;&quot;) + (link.cls ? ' class=&quot;' + link.cls + '&quot;' : &quot;&quot;) + '&gt;' + (link.label || &quot;&quot;) + '&lt;/a&gt;');</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/Logging.js">core/Logging.js</h2><div id="stats" class="high"><div class="percentage">84%</div><div class="sloc">25</div><div class="hits">21</div><div class="misses">4</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Logging Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * This module exposes the functions that configures the logging of calipso.</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * This is based entirely on Winston.</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">12</td><td class="hits">1</td><td class="source">var app, rootpath = process.cwd(),</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">  winstong = require('winston'),</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> * Core export</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">21</td><td class="hits">1</td><td class="source">exports = module.exports = {</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">  configureLogging: configureLogging</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> * Configure winston to provide the logging services.</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> * TODO : This can be factored out into a module.</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">32</td><td class="hits">1</td><td class="source">function configureLogging(options) {</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">34</td><td class="hits">3</td><td class="source">  options = options || calipso.config.get('logging');</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  //Configure logging</td></tr><tr class="hit"><td class="line">37</td><td class="hits">3</td><td class="source">  var logMsg = &quot;\x1b[36mLogging enabled: \x1b[0m&quot;,</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">      winston = require(&quot;winston&quot;);</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">40</td><td class="hits">3</td><td class="source">  try {</td></tr><tr class="hit"><td class="line">41</td><td class="hits">3</td><td class="source">    winston.remove(winston.transports.File);</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">  } catch (exFile) {</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">    // Ignore the fault</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">46</td><td class="hits">3</td><td class="source">  if (options.file &amp;&amp; options.file.enabled) {</td></tr><tr class="miss"><td class="line">47</td><td class="hits">0</td><td class="source">    winston.add(winston.transports.File, {</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">      level: options.console.level,</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">      timestamp: options.file.timestamp,</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">      filename: options.file.filepath</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">    });</td></tr><tr class="miss"><td class="line">52</td><td class="hits">0</td><td class="source">    logMsg += &quot;File @ &quot; + options.file.filepath + &quot; &quot;;</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">55</td><td class="hits">3</td><td class="source">  try {</td></tr><tr class="hit"><td class="line">56</td><td class="hits">3</td><td class="source">    winston.remove(winston.transports.Console);</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">  } catch (exConsole) {</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">    // Ignore the fault</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">61</td><td class="hits">3</td><td class="source">  if (options.console &amp;&amp; options.console.enabled) {</td></tr><tr class="miss"><td class="line">62</td><td class="hits">0</td><td class="source">    winston.add(winston.transports.Console, {</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">      level: options.console.level,</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">      timestamp: options.console.timestamp,</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">      colorize: options.console.colorize</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">    });</td></tr><tr class="miss"><td class="line">67</td><td class="hits">0</td><td class="source">    logMsg += &quot;Console &quot;;</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">  // Temporary data for form</td></tr><tr class="hit"><td class="line">71</td><td class="hits">3</td><td class="source">  calipso.data.loglevels = [];</td></tr><tr class="hit"><td class="line">72</td><td class="hits">3</td><td class="source">  for (var level in winston.config.npm.levels) {</td></tr><tr class="hit"><td class="line">73</td><td class="hits">18</td><td class="source">    calipso.data.loglevels.push(level);</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">  // Shortcuts to Default</td></tr><tr class="hit"><td class="line">77</td><td class="hits">3</td><td class="source">  calipso.log = winston.info; // Default function</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source">  // Shortcuts to NPM levels</td></tr><tr class="hit"><td class="line">79</td><td class="hits">3</td><td class="source">  calipso.silly = winston.silly;</td></tr><tr class="hit"><td class="line">80</td><td class="hits">3</td><td class="source">  calipso.verbose = winston.verbose;</td></tr><tr class="hit"><td class="line">81</td><td class="hits">3</td><td class="source">  calipso.info = winston.info;</td></tr><tr class="hit"><td class="line">82</td><td class="hits">3</td><td class="source">  calipso.warn = winston.warn;</td></tr><tr class="hit"><td class="line">83</td><td class="hits">3</td><td class="source">  calipso.debug = winston.debug;</td></tr><tr class="hit"><td class="line">84</td><td class="hits">3</td><td class="source">  calipso.error = winston.error;</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Menu.js">core/Menu.js</h2><div id="stats" class="high"><div class="percentage">98%</div><div class="sloc">143</div><div class="hits">141</div><div class="misses">2</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Menu Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * This library provides the base functions to manage the creation of menus.</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * A default renderer will be provided in this library, but this is intended to be over-ridden</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * By menu modules (e.g. to export different structures), or even source menus from different locations.</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> * Includes</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">15</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">  utils = require('connect').utils,</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">  merge = utils.merge,</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> * The default menu item object, with default configuration values.</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> * Constructor</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">26</td><td class="hits">1</td><td class="source">function CalipsoMenu(name, sort, type, options) {</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">  // Basic menu options, used typically for root menu holder</td></tr><tr class="hit"><td class="line">29</td><td class="hits">67</td><td class="source">  this.name = name || 'default'; // This should be mandatory</td></tr><tr class="hit"><td class="line">30</td><td class="hits">67</td><td class="source">  this.type = type || 'root';</td></tr><tr class="hit"><td class="line">31</td><td class="hits">67</td><td class="source">  this.sort = sort || 'name';</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  // Options for this menu item</td></tr><tr class="hit"><td class="line">34</td><td class="hits">67</td><td class="source">  if (options) {</td></tr><tr class="hit"><td class="line">35</td><td class="hits">51</td><td class="source">    this.setOptions(options);</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">  // Child menu items</td></tr><tr class="hit"><td class="line">39</td><td class="hits">67</td><td class="source">  this.children = {};</td></tr><tr class="hit"><td class="line">40</td><td class="hits">67</td><td class="source">  this.sortedChildren = []; // Sorted array of prop names for recursion</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source"> * Exports</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">46</td><td class="hits">1</td><td class="source">module.exports = CalipsoMenu;</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source"> * Wrapper to enable setting of menu options</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">51</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.setOptions = function(options) {</td></tr><tr class="hit"><td class="line">52</td><td class="hits">52</td><td class="source">  merge(this, options);</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> * Function to enable addition of a menu item to the menu.</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> * Menu Options:</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> * name: req.t('Admin')  -- Label to display</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> * path: admin -- the menu heirarchy path, used for parent child.</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source"> * e.g. path: admin/config -- the menu heirarchy path, used for parent child.</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> * instruction: req.t('Administration Menu') -- tooltip label</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> * url: '/admin'  -- Url to use as link</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source"> * security: [/admin/,&quot;bob&quot;] -- regex based on user role</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">66</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.addMenuItem = function(req, options) {</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">68</td><td class="hits">30</td><td class="source">  var self = this;</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">  // The req parameter was added in 0.3.0, if not passed, assuming options only</td></tr><tr class="hit"><td class="line">71</td><td class="hits">30</td><td class="source">  if (options === undefined) calipso.error(&quot;Attempting to add menu item with invalid params, please update your module for the 0.3.0 api, path: &quot; + req.path);</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">  // Check security</td></tr><tr class="hit"><td class="line">74</td><td class="hits">30</td><td class="source">  if (options.permit) {</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">76</td><td class="hits">28</td><td class="source">    var permitFn = new calipso.permission.Filter(options, options.permit),</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">        permit = permitFn.check(req);</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">79</td><td class="hits">28</td><td class="source">    if (typeof permit !== &quot;object&quot;) return;</td></tr><tr class="hit"><td class="line">80</td><td class="hits">29</td><td class="source">    if (!permit.allow) return;</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">  // Admin security is opposite to default</td></tr><tr class="hit"><td class="line">83</td><td class="hits">29</td><td class="source">  if (self.name === 'admin') {</td></tr><tr class="hit"><td class="line">84</td><td class="hits">1</td><td class="source">    var isAdmin = req.session.user &amp;&amp; req.session.user.isAdmin;</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source">    // Admin by default is not shown unless permitted</td></tr><tr class="hit"><td class="line">86</td><td class="hits">2</td><td class="source">    if (!options.permit &amp;&amp; !isAdmin) return;</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">  // Split the path, traverse items and add menuItems.</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">  // If you add a child prior to parent, then create the parent.</td></tr><tr class="hit"><td class="line">91</td><td class="hits">28</td><td class="source">  var newItem = self.createPath(options, options.path.split(&quot;/&quot;));</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> * Ensure that a full path provided is a valid menu tree</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">98</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.createPath = function(options, path) {</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">100</td><td class="hits">51</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">101</td><td class="hits">51</td><td class="source">  var currentItem = path[0];</td></tr><tr class="hit"><td class="line">102</td><td class="hits">51</td><td class="source">  var remainingItems = path.splice(1, path.length - 1);</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">104</td><td class="hits">51</td><td class="source">  if (self.children[currentItem] &amp;&amp; remainingItems.length &gt; 0) {</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">    // Recurse</td></tr><tr class="hit"><td class="line">107</td><td class="hits">18</td><td class="source">    self.children[currentItem].createPath(options, remainingItems);</td></tr><tr><td class="line">108</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source">    // If the current item does not yet exist</td></tr><tr class="hit"><td class="line">112</td><td class="hits">33</td><td class="source">    if (!self.children[currentItem]) {</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">      // Do we have children left, if so, mark this as a temporary node (e.g. we dont actually have its options)</td></tr><tr class="hit"><td class="line">115</td><td class="hits">31</td><td class="source">      if (remainingItems.length &gt; 0) {</td></tr><tr class="hit"><td class="line">116</td><td class="hits">5</td><td class="source">        self.children[currentItem] = new CalipsoMenu('Child of ' + currentItem, self.sort, 'temporary', options);</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">118</td><td class="hits">26</td><td class="source">        self.children[currentItem] = new CalipsoMenu('Child of ' + currentItem, self.sort, 'child', options);</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">      }</td></tr><tr class="hit"><td class="line">120</td><td class="hits">31</td><td class="source">      self.sortedChildren.push(currentItem); // Add to array for later sorting</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">    // Check to see if we need to update a temporary node</td></tr><tr class="hit"><td class="line">124</td><td class="hits">33</td><td class="source">    if (self.children[currentItem] &amp;&amp; remainingItems.length === 0 &amp;&amp; self.children[currentItem].type === 'temporary') {</td></tr><tr class="hit"><td class="line">125</td><td class="hits">1</td><td class="source">      self.children[currentItem].type = 'child';</td></tr><tr class="hit"><td class="line">126</td><td class="hits">1</td><td class="source">      self.children[currentItem].setOptions(options);</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">129</td><td class="hits">33</td><td class="source">    if (remainingItems.length &gt; 0) {</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">      // Recurse</td></tr><tr class="hit"><td class="line">131</td><td class="hits">5</td><td class="source">      self.children[currentItem].createPath(options, remainingItems);</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">  // Sort the sorted array</td></tr><tr class="hit"><td class="line">137</td><td class="hits">51</td><td class="source">  self.sortedChildren.sort(function(a, b) {</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">    // a &amp; b are strings, but both objects on the current children</td></tr><tr class="hit"><td class="line">140</td><td class="hits">9</td><td class="source">    var diff;</td></tr><tr class="hit"><td class="line">141</td><td class="hits">9</td><td class="source">    if (self.children[a][self.sort] &amp;&amp; self.children[b][self.sort]) {</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">143</td><td class="hits">8</td><td class="source">      if (typeof self.children[a][self.sort] === &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">144</td><td class="hits">7</td><td class="source">        diff = self.children[a][self.sort].toLowerCase() &gt; self.children[b][self.sort].toLowerCase();</td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">146</td><td class="hits">1</td><td class="source">        diff = self.children[a][self.sort] &gt; self.children[b][self.sort];</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">150</td><td class="hits">1</td><td class="source">      diff = self.children[a].name.toLowerCase() &gt; self.children[b].name.toLowerCase();</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">153</td><td class="hits">9</td><td class="source">    return diff;</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source"> * Render the menu as a html list - this is the default.</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> * The idea is that this can be over-ridden (or the sub-function), to control</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source"> * HTML generation.</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">165</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.render = function(req, depth) {</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">167</td><td class="hits">13</td><td class="source">  var self = this;</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">  // If the menu is empty, render nothing</td></tr><tr class="hit"><td class="line">170</td><td class="hits">25</td><td class="source">  if (self.sortedChildren.length === 0) return '';</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">  // Get selected items</td></tr><tr class="hit"><td class="line">173</td><td class="hits">1</td><td class="source">  var selected = self.selected(req);</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">175</td><td class="hits">1</td><td class="source">  var htmlOutput = '';</td></tr><tr class="hit"><td class="line">176</td><td class="hits">1</td><td class="source">  htmlOutput += self.startTag();</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">178</td><td class="hits">1</td><td class="source">  var renderUp = function(menu) {</td></tr><tr class="hit"><td class="line">179</td><td class="hits">5</td><td class="source">      var selectedClass = '';</td></tr><tr class="hit"><td class="line">180</td><td class="hits">5</td><td class="source">      if (contains(selected, menu.path)) {</td></tr><tr class="hit"><td class="line">181</td><td class="hits">2</td><td class="source">        selectedClass = '-selected';</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source">      }</td></tr><tr class="hit"><td class="line">183</td><td class="hits">5</td><td class="source">      var html = self.menuStartTag(menu, selectedClass) + self.menuLinkTag(req, menu, selectedClass);</td></tr><tr class="hit"><td class="line">184</td><td class="hits">5</td><td class="source">      return html;</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">187</td><td class="hits">1</td><td class="source">  var renderDown = function(menu) {</td></tr><tr class="hit"><td class="line">188</td><td class="hits">5</td><td class="source">      var html = self.menuEndTag(menu);</td></tr><tr class="hit"><td class="line">189</td><td class="hits">5</td><td class="source">      return html;</td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">192</td><td class="hits">1</td><td class="source">  var renderStart = function(menu) {</td></tr><tr class="hit"><td class="line">193</td><td class="hits">3</td><td class="source">      var html = self.childrenStartTag(menu);</td></tr><tr class="hit"><td class="line">194</td><td class="hits">3</td><td class="source">      return html;</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">197</td><td class="hits">1</td><td class="source">  var renderFinish = function(menu) {</td></tr><tr class="hit"><td class="line">198</td><td class="hits">3</td><td class="source">      var html = self.childrenEndTag(menu);</td></tr><tr class="hit"><td class="line">199</td><td class="hits">3</td><td class="source">      return html;</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">202</td><td class="hits">1</td><td class="source">  var output = [];</td></tr><tr class="hit"><td class="line">203</td><td class="hits">1</td><td class="source">  self.fnRecurse(self, renderUp, renderDown, renderStart, renderFinish, depth, output);</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">205</td><td class="hits">1</td><td class="source">  htmlOutput += output.join(&quot;&quot;);</td></tr><tr class="hit"><td class="line">206</td><td class="hits">1</td><td class="source">  htmlOutput += self.endTag();</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">208</td><td class="hits">1</td><td class="source">  return htmlOutput;</td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source"> * Specific tag rendering functions</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source"> * Over-write to enable custom menu rendering</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">216</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.startTag = function() {</td></tr><tr class="hit"><td class="line">217</td><td class="hits">1</td><td class="source">  return &quot;&lt;ul id='&quot; + this.name + &quot;-menu' class='menu&quot; + (this.cls ? ' ' + this.cls : '') + &quot;'&gt;&quot;;</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">219</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.endTag = function() {</td></tr><tr class="hit"><td class="line">220</td><td class="hits">1</td><td class="source">  return &quot;&lt;/ul&gt;&quot;;</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">222</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.menuStartTag = function(menu, selected) {</td></tr><tr class="hit"><td class="line">223</td><td class="hits">5</td><td class="source">  var menuItemTagId = menu.path.replace(/\//g, '-') + &quot;-menu-item&quot;;</td></tr><tr class="hit"><td class="line">224</td><td class="hits">5</td><td class="source">  return &quot;&lt;li id='&quot; + menuItemTagId + &quot;' class='&quot; + this.name + &quot;-menu-item&quot; + selected + &quot;'&gt;&quot;;</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">226</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.menuLinkTag = function(req, menu, selected) {</td></tr><tr class="hit"><td class="line">227</td><td class="hits">5</td><td class="source">  return &quot;&lt;a href='&quot; + menu.url + &quot;' title='&quot; + req.t(menu.description) + &quot;' class='&quot; + this.name + &quot;-menu-link&quot; + selected + (menu.cls ? &quot; &quot; + menu.cls : &quot;&quot;) + &quot;'&gt;&quot; + req.t(menu.name) + &quot;&lt;/a&gt;&quot;;</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">229</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.menuEndTag = function(menu) {</td></tr><tr class="hit"><td class="line">230</td><td class="hits">5</td><td class="source">  return &quot;&lt;/li&gt;&quot;;</td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">232</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.childrenStartTag = function() {</td></tr><tr class="hit"><td class="line">233</td><td class="hits">3</td><td class="source">  return &quot;&lt;ul&gt;&quot;;</td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source">};</td></tr><tr class="hit"><td class="line">235</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.childrenEndTag = function() {</td></tr><tr class="hit"><td class="line">236</td><td class="hits">3</td><td class="source">  return &quot;&lt;/ul&gt;&quot;;</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">240</td><td class="hits"></td><td class="source"> * Locate selected paths based on current request</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">242</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.selected = function(req) {</td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source">  // Based on current url, create a regex string that can be used to test if a menu item</td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">  // Is selected during rendering</td></tr><tr class="hit"><td class="line">246</td><td class="hits">2</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">247</td><td class="hits">2</td><td class="source">  var output = [];</td></tr><tr><td class="line">248</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">249</td><td class="hits">2</td><td class="source">  var selectedFn = function(menu) {</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">251</td><td class="hits">10</td><td class="source">      var menuSplit = menu.url.split(&quot;/&quot;);</td></tr><tr class="hit"><td class="line">252</td><td class="hits">10</td><td class="source">      var reqSplit = req.url.split(&quot;/&quot;);</td></tr><tr class="hit"><td class="line">253</td><td class="hits">10</td><td class="source">      var match = true;</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">255</td><td class="hits">10</td><td class="source">      menuSplit.forEach(function(value, key) {</td></tr><tr class="hit"><td class="line">256</td><td class="hits">36</td><td class="source">        match = match &amp;&amp; (value === reqSplit[key]);</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source">      // Check if the url matches</td></tr><tr class="hit"><td class="line">260</td><td class="hits">10</td><td class="source">      if (match) {</td></tr><tr class="hit"><td class="line">261</td><td class="hits">4</td><td class="source">        return menu.path;</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">266</td><td class="hits">2</td><td class="source">  self.fnRecurse(self, selectedFn, output);</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">268</td><td class="hits">2</td><td class="source">  return output;</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">273</td><td class="hits"></td><td class="source"> * Helper function that can recurse the menu tree</td></tr><tr><td class="line">274</td><td class="hits"></td><td class="source"> * From a start point, execute a function and add the result to an output array</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">276</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.fnRecurse = function(menu, fnUp, fnDown, fnStart, fnFinish, depth, output) {</td></tr><tr><td class="line">277</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">278</td><td class="hits">24</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">279</td><td class="hits">24</td><td class="source">  var result;</td></tr><tr class="hit"><td class="line">280</td><td class="hits">24</td><td class="source">  if (typeof fnDown != 'function') {</td></tr><tr class="hit"><td class="line">281</td><td class="hits">18</td><td class="source">    output = fnDown;</td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">283</td><td class="hits">24</td><td class="source">  output = output || [];</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source">  // Recurse from menu item selected</td></tr><tr class="hit"><td class="line">286</td><td class="hits">24</td><td class="source">  if (menu.type === 'root') {</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">288</td><td class="hits"></td><td class="source">    // Functions don't run on root</td></tr><tr class="hit"><td class="line">289</td><td class="hits">4</td><td class="source">    menu.sortedChildren.forEach(function(child) {</td></tr><tr class="hit"><td class="line">290</td><td class="hits">4</td><td class="source">      self.fnRecurse(menu.children[child], fnUp, fnDown, fnStart, fnFinish, depth, output);</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">294</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source">    // Control depth of recursion</td></tr><tr class="hit"><td class="line">296</td><td class="hits">20</td><td class="source">    depth = depth === undefined ? -1 : depth;</td></tr><tr class="hit"><td class="line">297</td><td class="hits">20</td><td class="source">    if (depth &gt; 0) {</td></tr><tr class="miss"><td class="line">298</td><td class="hits">0</td><td class="source">      depth = depth - 1;</td></tr><tr class="hit"><td class="line">299</td><td class="hits">20</td><td class="source">    } else if (depth === -1) {</td></tr><tr><td class="line">300</td><td class="hits"></td><td class="source">      // Recures infinitely</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">302</td><td class="hits">0</td><td class="source">      return output;</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">305</td><td class="hits"></td><td class="source">    // Count the number of children</td></tr><tr class="hit"><td class="line">306</td><td class="hits">20</td><td class="source">    var childCount = menu.sortedChildren.length;</td></tr><tr><td class="line">307</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">308</td><td class="hits"></td><td class="source">    // Execute fn</td></tr><tr class="hit"><td class="line">309</td><td class="hits">20</td><td class="source">    if (typeof fnUp === 'function') {</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">311</td><td class="hits">20</td><td class="source">      result = fnUp(menu);</td></tr><tr class="hit"><td class="line">312</td><td class="hits">20</td><td class="source">      if (result) {</td></tr><tr class="hit"><td class="line">313</td><td class="hits">14</td><td class="source">        output.push(result);</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">315</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">316</td><td class="hits">20</td><td class="source">      if (childCount &gt; 0) {</td></tr><tr class="hit"><td class="line">317</td><td class="hits">12</td><td class="source">        if (typeof fnStart === 'function') {</td></tr><tr class="hit"><td class="line">318</td><td class="hits">3</td><td class="source">          result = fnStart(menu);</td></tr><tr class="hit"><td class="line">319</td><td class="hits">3</td><td class="source">          if (result) {</td></tr><tr class="hit"><td class="line">320</td><td class="hits">3</td><td class="source">            output.push(result);</td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">322</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">323</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source">    // Recurse</td></tr><tr class="hit"><td class="line">328</td><td class="hits">20</td><td class="source">    menu.sortedChildren.forEach(function(child) {</td></tr><tr class="hit"><td class="line">329</td><td class="hits">16</td><td class="source">      self.fnRecurse(menu.children[child], fnUp, fnDown, fnStart, fnFinish, depth, output);</td></tr><tr><td class="line">330</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">332</td><td class="hits"></td><td class="source">    // Close</td></tr><tr class="hit"><td class="line">333</td><td class="hits">20</td><td class="source">    if (typeof fnDown === 'function') {</td></tr><tr><td class="line">334</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">335</td><td class="hits">5</td><td class="source">      result = fnDown(menu);</td></tr><tr class="hit"><td class="line">336</td><td class="hits">5</td><td class="source">      if (result) {</td></tr><tr class="hit"><td class="line">337</td><td class="hits">5</td><td class="source">        output.push(result);</td></tr><tr><td class="line">338</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">340</td><td class="hits">5</td><td class="source">      if (childCount &gt; 0) {</td></tr><tr class="hit"><td class="line">341</td><td class="hits">3</td><td class="source">        if (typeof fnFinish === 'function') {</td></tr><tr class="hit"><td class="line">342</td><td class="hits">3</td><td class="source">          result = fnFinish(menu);</td></tr><tr class="hit"><td class="line">343</td><td class="hits">3</td><td class="source">          if (result) {</td></tr><tr class="hit"><td class="line">344</td><td class="hits">3</td><td class="source">            output.push(result);</td></tr><tr><td class="line">345</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">346</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">347</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">350</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">354</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source"> * Return current menu as a JSON object, used for Ajax style menus.</td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source"> * Path : root to return menu from, default is root (entire menu)</td></tr><tr><td class="line">357</td><td class="hits"></td><td class="source"> * Depth : How many levels to return menu</td></tr><tr><td class="line">358</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">359</td><td class="hits">1</td><td class="source">CalipsoMenu.prototype.getMenuJson = function(path, depth) {</td></tr><tr><td class="line">360</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">361</td><td class="hits"></td><td class="source">  // TODO</td></tr><tr><td class="line">362</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">364</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">365</td><td class="hits"></td><td class="source"> * Private helper functions</td></tr><tr><td class="line">366</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">367</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">368</td><td class="hits">1</td><td class="source">function contains(a, obj) {</td></tr><tr class="hit"><td class="line">369</td><td class="hits">5</td><td class="source">  var i = a.length;</td></tr><tr class="hit"><td class="line">370</td><td class="hits">5</td><td class="source">  while (i--) {</td></tr><tr class="hit"><td class="line">371</td><td class="hits">9</td><td class="source">    if (a[i] === obj) {</td></tr><tr class="hit"><td class="line">372</td><td class="hits">2</td><td class="source">      return true;</td></tr><tr><td class="line">373</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">374</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">375</td><td class="hits">3</td><td class="source">  return false;</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Module.js">core/Module.js</h2><div id="stats" class="high"><div class="percentage">86%</div><div class="sloc">258</div><div class="hits">222</div><div class="misses">36</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr class="hit"><td class="line">1</td><td class="hits">1</td><td class="source">var app, rootpath = process.cwd() + '/',</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source">  mongoStore = require(path.join(rootpath, 'support/connect-mongodb')),</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source">  mongoose = require('mongoose');</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * Route all of the modules based on the module event model</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * This replaces an earlier version that only executed modules in</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * parallel via step</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">13</td><td class="hits">1</td><td class="source">function eventRouteModules(req, res, next) {</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">  // Ignore static content</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">  // TODO : Make this more connect friendly or at least configurable</td></tr><tr class="hit"><td class="line">17</td><td class="hits">4</td><td class="source">  if (req.url.match(/^\/images|^\/js|^\/css|^\/favicon.ico|png$|jpg$|gif$|css$|js$/)) {</td></tr><tr class="miss"><td class="line">18</td><td class="hits">0</td><td class="source">    return next();</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">21</td><td class="hits">4</td><td class="source">  req.timeStart = new Date();</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">  // Attach our event listener to this request</td></tr><tr class="hit"><td class="line">24</td><td class="hits">4</td><td class="source">  attachRequestEvents(req, res);</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">  // Initialise the response re. matches</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">  // Later used to decide to show 404</td></tr><tr class="hit"><td class="line">28</td><td class="hits">4</td><td class="source">  res.routeMatched = false;</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">  // Store our callback here</td></tr><tr class="hit"><td class="line">31</td><td class="hits">4</td><td class="source">  req.routeComplete = function(res) {</td></tr><tr class="hit"><td class="line">32</td><td class="hits">8</td><td class="source">    if(!res.finished) next();</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">  // Route 'first' modules that fire before all others</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  // These first modules can stop the routing of all others </td></tr><tr class="hit"><td class="line">37</td><td class="hits">4</td><td class="source">  doFirstModules(req, res, function(err) {</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">39</td><td class="hits">4</td><td class="source">    var iterator = function(module, cb) {</td></tr><tr class="hit"><td class="line">40</td><td class="hits">16</td><td class="source">       routeModule(req, res, module, false, false, cb);</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">43</td><td class="hits">4</td><td class="source">    calipso.lib.async.map(calipso.lib._.keys(calipso.modules), iterator, function(err, result) {</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">      // Not important</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">    })</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> * Attach module event emitters and request event listener</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> * to this request instance.</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> * This will only last for the context of a current request</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">57</td><td class="hits">1</td><td class="source">function attachRequestEvents(req, res) {</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">  // Create a request event listener for this request, pass in functions </td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">  // to enable testing.</td></tr><tr class="hit"><td class="line">61</td><td class="hits">4</td><td class="source">  req.event = new calipso.event.RequestEventListener({</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">    notifyDependencyFn: notifyDependenciesOfRoute,</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">    registerDependenciesFn: registerDependencies</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">  // </td></tr><tr class="hit"><td class="line">67</td><td class="hits">4</td><td class="source">  var maxListeners = calipso.config.get('server:events:maxListeners');</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">  // Attach all the modules to it</td></tr><tr class="hit"><td class="line">70</td><td class="hits">4</td><td class="source">  for (var module in calipso.modules) {</td></tr><tr class="hit"><td class="line">71</td><td class="hits">16</td><td class="source">    req.event.registerModule(req, res, module, {maxListeners: maxListeners});</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> * Helper to register dependent modules that should be checked by a module when</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> * routing, the parent module's emitter is passed in.</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">80</td><td class="hits">1</td><td class="source">function registerDependencies(moduleEmitter, moduleName) {</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">  // Register depends on parent</td></tr><tr class="hit"><td class="line">83</td><td class="hits">16</td><td class="source">  if (calipso.modules[moduleName].fn &amp;&amp; calipso.modules[moduleName].fn.depends) {</td></tr><tr class="hit"><td class="line">84</td><td class="hits">4</td><td class="source">    calipso.modules[moduleName].fn.depends.forEach(function(dependentModule) {</td></tr><tr class="hit"><td class="line">85</td><td class="hits">4</td><td class="source">      moduleEmitter.modules[moduleName].check[dependentModule] = false;</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">  }  </td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> * Route a specific module</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source"> * Called by both the eventRouteModules but also by when dependencies trigger</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> * a module to be routed</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> * req, res : request/resposne</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> * module : the module to route</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> * depends : has this route been triggered by an event based on dependencies being met</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> * last : final modules, after all others have routed</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">102</td><td class="hits">1</td><td class="source">function routeModule(req, res, moduleName, depends, last, next) {</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">104</td><td class="hits">20</td><td class="source">  var module = calipso.modules[moduleName];</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">  // If module is enabled and has no dependencies, or if we are explicitly triggering this via depends</td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">  // Ignore modules that are specified as post route only</td></tr><tr class="hit"><td class="line">108</td><td class="hits">20</td><td class="source">  if (module.enabled &amp;&amp; (depends || !module.fn.depends) &amp;&amp; (last || !module.fn.last) &amp;&amp; !module.fn.first) {</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">    // Fire event to start</td></tr><tr class="hit"><td class="line">111</td><td class="hits">8</td><td class="source">    req.event.modules[moduleName].route_start();</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">    // Route</td></tr><tr class="hit"><td class="line">114</td><td class="hits">8</td><td class="source">    module.fn.route(req, res, module, calipso.app, function(err, moduleName) {</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">      // Gracefully deal with errors</td></tr><tr class="hit"><td class="line">117</td><td class="hits">8</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">118</td><td class="hits">0</td><td class="source">        res.statusCode = 500;</td></tr><tr class="miss"><td class="line">119</td><td class="hits">0</td><td class="source">        calipso.error(err.message);</td></tr><tr class="miss"><td class="line">120</td><td class="hits">0</td><td class="source">        res.errorMessage = &quot;Module &quot; + moduleName + &quot;, error: &quot; + err.message + err.stack;</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">      // Expose configuration if module has it</td></tr><tr class="hit"><td class="line">124</td><td class="hits">8</td><td class="source">      if (module.fn &amp;&amp; module.fn.config) {</td></tr><tr class="miss"><td class="line">125</td><td class="hits">0</td><td class="source">        var modulePermit = calipso.permission.Helper.hasPermission(&quot;admin:module:configuration&quot;);</td></tr><tr class="miss"><td class="line">126</td><td class="hits">0</td><td class="source">        res.menu.admin.addMenuItem(req, {</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">          name: moduleName,</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source">          path: 'admin/modules/' + moduleName,</td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">          url: '/admin/modules?module=' + moduleName,</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">          description: 'Manage ' + moduleName + ' settings ...',</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">          permit: modulePermit</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">      // Finish event</td></tr><tr class="hit"><td class="line">136</td><td class="hits">8</td><td class="source">      req.event.modules[moduleName].route_finish();</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">      // Check to see if we have completed routing all modules</td></tr><tr class="hit"><td class="line">139</td><td class="hits">8</td><td class="source">      if (!last) {</td></tr><tr class="hit"><td class="line">140</td><td class="hits">8</td><td class="source">        checkAllModulesRouted(req, res);</td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">143</td><td class="hits">8</td><td class="source">      next();</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">149</td><td class="hits">12</td><td class="source">    checkAllModulesRouted(req, res);</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">151</td><td class="hits">12</td><td class="source">    next();</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source"> * Check that all enabled modules have been initialised</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source"> * Don't check disabled modules or modules that are setup for postRoute only</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">161</td><td class="hits">1</td><td class="source">function checkAllModulesRouted(req, res) {</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">163</td><td class="hits">20</td><td class="source">  var allRouted = true;</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">165</td><td class="hits">20</td><td class="source">  for (var module in req.event.modules) {</td></tr><tr class="hit"><td class="line">166</td><td class="hits">80</td><td class="source">    var moduleRouted = (req.event.modules[module].routed || (calipso.modules[module].enabled &amp;&amp; (calipso.modules[module].fn.last || calipso.modules[module].fn.first)) || !calipso.modules[module].enabled);</td></tr><tr class="hit"><td class="line">167</td><td class="hits">80</td><td class="source">    allRouted = moduleRouted &amp;&amp; allRouted;</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">170</td><td class="hits">20</td><td class="source">  if (allRouted &amp;&amp; !req.event.routeComplete) {</td></tr><tr class="hit"><td class="line">171</td><td class="hits">4</td><td class="source">    req.event.routeComplete = true;</td></tr><tr class="hit"><td class="line">172</td><td class="hits">4</td><td class="source">    doLastModules(req, res, function() {</td></tr><tr class="hit"><td class="line">173</td><td class="hits">4</td><td class="source">      req.timeFinish = new Date();</td></tr><tr class="hit"><td class="line">174</td><td class="hits">4</td><td class="source">      req.timeDuration = req.timeFinish - req.timeStart;</td></tr><tr class="hit"><td class="line">175</td><td class="hits">4</td><td class="source">      calipso.silly(&quot;All modules routed in &quot; + req.timeDuration + &quot; ms&quot;);</td></tr><tr class="hit"><td class="line">176</td><td class="hits">4</td><td class="source">      doResponse(req, res);</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source"> * RUn any modules that are defined as first routing modules</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source"> * via first: true, dependencies are ignored for these.</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">187</td><td class="hits">1</td><td class="source">function doFirstModules(req, res, next) {</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source">  // Get all the postRoute modules</td></tr><tr class="hit"><td class="line">190</td><td class="hits">4</td><td class="source">  var firstModules = [];</td></tr><tr class="hit"><td class="line">191</td><td class="hits">4</td><td class="source">  for (var moduleName in calipso.modules) {</td></tr><tr class="hit"><td class="line">192</td><td class="hits">16</td><td class="source">    if (calipso.modules[moduleName].enabled &amp;&amp; calipso.modules[moduleName].fn.first) {</td></tr><tr class="hit"><td class="line">193</td><td class="hits">4</td><td class="source">      firstModules.push(calipso.modules[moduleName]);</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">198</td><td class="hits">4</td><td class="source">  if(firstModules.length === 0) return next();</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">  // Execute their routing functions</td></tr><tr class="hit"><td class="line">201</td><td class="hits">4</td><td class="source">  calipso.lib.step(</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">  function doFirstModules() {</td></tr><tr class="hit"><td class="line">204</td><td class="hits">4</td><td class="source">    var group = this.group();</td></tr><tr class="hit"><td class="line">205</td><td class="hits">4</td><td class="source">    firstModules.forEach(function(module) {</td></tr><tr class="hit"><td class="line">206</td><td class="hits">4</td><td class="source">      module.fn.route(req, res, module, calipso.app, group());</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">  }, function done(err) {</td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">    // Gracefully deal with errors</td></tr><tr class="hit"><td class="line">211</td><td class="hits">4</td><td class="source">    if (err) {</td></tr><tr class="miss"><td class="line">212</td><td class="hits">0</td><td class="source">      res.statusCode = 500;</td></tr><tr class="miss"><td class="line">213</td><td class="hits">0</td><td class="source">      console.log(err.message);</td></tr><tr class="miss"><td class="line">214</td><td class="hits">0</td><td class="source">      res.errorMessage = err.message + err.stack;</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">217</td><td class="hits">4</td><td class="source">    next();</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">220</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source"> * RUn any modules that are defined as last routing modules</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source"> * via last: true, dependencies are ignored for these atm.</td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">229</td><td class="hits">1</td><td class="source">function doLastModules(req, res, next) {</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source">  // Get all the postRoute modules</td></tr><tr class="hit"><td class="line">232</td><td class="hits">4</td><td class="source">  var lastModules = [];</td></tr><tr class="hit"><td class="line">233</td><td class="hits">4</td><td class="source">  for (var moduleName in calipso.modules) {</td></tr><tr class="hit"><td class="line">234</td><td class="hits">16</td><td class="source">    if (calipso.modules[moduleName].enabled &amp;&amp; calipso.modules[moduleName].fn.last) {</td></tr><tr class="hit"><td class="line">235</td><td class="hits">4</td><td class="source">      lastModules.push(calipso.modules[moduleName]);</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">240</td><td class="hits">4</td><td class="source">  if(lastModules.length === 0) return next();</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source">  // Execute their routing functions</td></tr><tr class="hit"><td class="line">243</td><td class="hits">4</td><td class="source">  calipso.lib.step(</td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">  function doLastModules() {</td></tr><tr class="hit"><td class="line">246</td><td class="hits">4</td><td class="source">    var group = this.group();</td></tr><tr class="hit"><td class="line">247</td><td class="hits">4</td><td class="source">    lastModules.forEach(function(module) {</td></tr><tr class="hit"><td class="line">248</td><td class="hits">4</td><td class="source">      module.fn.route(req, res, module, calipso.app, group());</td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source">  }, function done(err) {</td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source">    // Gracefully deal with errors</td></tr><tr class="hit"><td class="line">253</td><td class="hits">4</td><td class="source">    if (err) {</td></tr><tr class="miss"><td class="line">254</td><td class="hits">0</td><td class="source">      res.statusCode = 500;</td></tr><tr class="miss"><td class="line">255</td><td class="hits">0</td><td class="source">      console.log(err.message);</td></tr><tr class="miss"><td class="line">256</td><td class="hits">0</td><td class="source">      res.errorMessage = err.message + err.stack;</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">259</td><td class="hits">4</td><td class="source">    next();</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source"> * Standard response to all modules completing their routing</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">269</td><td class="hits">1</td><td class="source">function doResponse(req, res, next) {</td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source">  // If we are in install mode, and are not in the installation process, then redirect</td></tr><tr class="hit"><td class="line">272</td><td class="hits">4</td><td class="source">  if (!calipso.config.get('installed') &amp;&amp; !req.url.match(/^\/admin\/install/)) {</td></tr><tr class="miss"><td class="line">273</td><td class="hits">0</td><td class="source">    calipso.silly(&quot;Redirecting to admin/install ...&quot;);</td></tr><tr class="miss"><td class="line">274</td><td class="hits">0</td><td class="source">    calipso.app.doingInstall = true;</td></tr><tr class="miss"><td class="line">275</td><td class="hits">0</td><td class="source">    res.redirect(&quot;/admin/install&quot;);</td></tr><tr class="miss"><td class="line">276</td><td class="hits">0</td><td class="source">    return;</td></tr><tr><td class="line">277</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source">  // If nothing could be matched ...</td></tr><tr class="hit"><td class="line">280</td><td class="hits">4</td><td class="source">  if (!res.routeMatched) {</td></tr><tr class="hit"><td class="line">281</td><td class="hits">1</td><td class="source">    calipso.log(&quot;No Calipso module routes matched the current URL.&quot;);</td></tr><tr class="hit"><td class="line">282</td><td class="hits">1</td><td class="source">    res.statusCode = 404;</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source">  // Render statuscodes dealt with by themeing engine</td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source">  // TODO - this is not very clean</td></tr><tr class="hit"><td class="line">287</td><td class="hits">4</td><td class="source">  if (res.statusCode === 404 || res.statusCode === 500 || res.statusCode === 200) {</td></tr><tr><td class="line">288</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">289</td><td class="hits">3</td><td class="source">    calipso.theme.render(req, res, function(err, content) {</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">291</td><td class="hits">3</td><td class="source">      if (err) {</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source">        // Something went wrong at the layout, cannot use layout to render.</td></tr><tr class="miss"><td class="line">294</td><td class="hits">0</td><td class="source">        res.statusCode = 500;</td></tr><tr class="miss"><td class="line">295</td><td class="hits">0</td><td class="source">        res.send(&quot;&lt;html&gt;&lt;h2&gt;A fatal error occurred!&lt;/h2&gt;&quot; + &quot;&lt;p&gt;&quot; + (err.xMessage ? err.xMessage : err.message) + &quot;&lt;/p&gt;&quot; + &quot;&lt;pre&gt;&quot; + err.stack + &quot;&lt;/pre&gt;&lt;/html&gt;&quot;);</td></tr><tr class="miss"><td class="line">296</td><td class="hits">0</td><td class="source">        req.routeComplete(res);</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source">      } else {</td></tr><tr><td class="line">299</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">300</td><td class="hits">3</td><td class="source">        res.setHeader('Content-Type', 'text/html');</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source">        // Who am I?</td></tr><tr class="hit"><td class="line">302</td><td class="hits">3</td><td class="source">        res.setHeader('X-Powered-By', 'Calipso');</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source">        // render</td></tr><tr class="hit"><td class="line">305</td><td class="hits">3</td><td class="source">        res.send(content);</td></tr><tr><td class="line">306</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">307</td><td class="hits"></td><td class="source">        // Callback</td></tr><tr class="hit"><td class="line">308</td><td class="hits">3</td><td class="source">        req.routeComplete(res);</td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">311</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">312</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">313</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">315</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source">    // Otherwise, provided we haven't already issued a redirect, then pass back to Express</td></tr><tr class="hit"><td class="line">317</td><td class="hits">1</td><td class="source">    req.routeComplete(res);</td></tr><tr><td class="line">318</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">319</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">321</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">322</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">323</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source"> * Initialise the modules currently enabled.</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> * This iterates through the modules loaded by loadModules (it places them in an array in the calipso object),</td></tr><tr><td class="line">327</td><td class="hits"></td><td class="source"> * and calls the 'init' function exposed by each module (in parallel controlled via step).</td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">330</td><td class="hits">1</td><td class="source">function initModules() {</td></tr><tr><td class="line">331</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">332</td><td class="hits"></td><td class="source">  // Reset</td></tr><tr class="hit"><td class="line">333</td><td class="hits">2</td><td class="source">  calipso.initComplete = false;</td></tr><tr><td class="line">334</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">335</td><td class="hits"></td><td class="source">  // Create a list of all our enabled modules</td></tr><tr class="hit"><td class="line">336</td><td class="hits">2</td><td class="source">  var enabledModules = [];</td></tr><tr class="hit"><td class="line">337</td><td class="hits">2</td><td class="source">  for (var module in calipso.modules) {</td></tr><tr class="hit"><td class="line">338</td><td class="hits">8</td><td class="source">    if (calipso.modules[module].enabled) {</td></tr><tr class="hit"><td class="line">339</td><td class="hits">8</td><td class="source">      enabledModules.push(module);</td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">341</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">342</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">343</td><td class="hits"></td><td class="source">  // Initialise them all</td></tr><tr class="hit"><td class="line">344</td><td class="hits">2</td><td class="source">  enabledModules.forEach(function(module) {</td></tr><tr class="hit"><td class="line">345</td><td class="hits">8</td><td class="source">    initModule(module, false);</td></tr><tr><td class="line">346</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">347</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">350</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source"> * Init a specific module, called by event listeners re. dependent modules</td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">354</td><td class="hits">1</td><td class="source">function initModule(module, depends) {</td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">357</td><td class="hits"></td><td class="source">  // If the module has no dependencies, kick start it</td></tr><tr class="hit"><td class="line">358</td><td class="hits">10</td><td class="source">  if (depends || !calipso.modules[module].fn.depends) {</td></tr><tr><td class="line">359</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">360</td><td class="hits"></td><td class="source">    // Init start event</td></tr><tr class="hit"><td class="line">361</td><td class="hits">8</td><td class="source">    calipso.modules[module].event.init_start();</td></tr><tr><td class="line">362</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">363</td><td class="hits"></td><td class="source">    // Next run any init functions</td></tr><tr class="hit"><td class="line">364</td><td class="hits">8</td><td class="source">    calipso.modules[module].fn.init(calipso.modules[module], calipso.app, function(err) {</td></tr><tr><td class="line">365</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">366</td><td class="hits"></td><td class="source">      // Init finish event</td></tr><tr class="hit"><td class="line">367</td><td class="hits">8</td><td class="source">      calipso.modules[module].inited = true;</td></tr><tr class="hit"><td class="line">368</td><td class="hits">8</td><td class="source">      calipso.modules[module].event.init_finish();</td></tr><tr><td class="line">369</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source">      // Now, load any routes to go along with it</td></tr><tr class="hit"><td class="line">371</td><td class="hits">8</td><td class="source">      if (calipso.modules[module].fn.routes &amp;&amp; calipso.modules[module].fn.routes.length &gt; 0) {</td></tr><tr class="hit"><td class="line">372</td><td class="hits">2</td><td class="source">        calipso.lib.async.map(calipso.modules[module].fn.routes, function(options, next) {</td></tr><tr class="hit"><td class="line">373</td><td class="hits">2</td><td class="source">          calipso.modules[module].router.addRoute(options, next);</td></tr><tr><td class="line">374</td><td class="hits"></td><td class="source">        }, function(err, data) {</td></tr><tr class="hit"><td class="line">375</td><td class="hits">2</td><td class="source">          if (err) calipso.error(err);</td></tr><tr class="hit"><td class="line">376</td><td class="hits">2</td><td class="source">          checkAllModulesInited();</td></tr><tr><td class="line">377</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">378</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">379</td><td class="hits">6</td><td class="source">        checkAllModulesInited();</td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">381</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">382</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">383</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">384</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">385</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">386</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">387</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">388</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">389</td><td class="hits"></td><td class="source"> * Check that all enabled modules have been initialised</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source"> * If they have been initialised, then call the callback supplied on initialisation</td></tr><tr><td class="line">391</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">392</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">393</td><td class="hits">1</td><td class="source">function checkAllModulesInited() {</td></tr><tr><td class="line">394</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">395</td><td class="hits">8</td><td class="source">  var allLoaded = true;</td></tr><tr class="hit"><td class="line">396</td><td class="hits">8</td><td class="source">  for (var module in calipso.modules) {</td></tr><tr class="hit"><td class="line">397</td><td class="hits">32</td><td class="source">    allLoaded = (calipso.modules[module].inited || !calipso.modules[module].enabled) &amp;&amp; allLoaded;</td></tr><tr><td class="line">398</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">399</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">400</td><td class="hits">8</td><td class="source">  if (allLoaded &amp;&amp; !calipso.initComplete) {</td></tr><tr class="hit"><td class="line">401</td><td class="hits">2</td><td class="source">    calipso.initComplete = true;</td></tr><tr class="hit"><td class="line">402</td><td class="hits">2</td><td class="source">    calipso.initCallback();</td></tr><tr><td class="line">403</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">404</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">405</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">406</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">407</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">408</td><td class="hits"></td><td class="source"> * Load the modules from the file system, into a 'modules' array</td></tr><tr><td class="line">409</td><td class="hits"></td><td class="source"> * that can be managed and iterated.</td></tr><tr><td class="line">410</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">411</td><td class="hits"></td><td class="source"> * The first level folder is the module type (e.g. core, contrib, ui).</td></tr><tr><td class="line">412</td><td class="hits"></td><td class="source"> * It doesn't actually change the processing, but that folder structure is</td></tr><tr><td class="line">413</td><td class="hits"></td><td class="source"> * now stored as a property of the module (so makes admin easier).</td></tr><tr><td class="line">414</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">415</td><td class="hits"></td><td class="source"> * It will take in an options object that holds the configuration parameters</td></tr><tr><td class="line">416</td><td class="hits"></td><td class="source"> * for the modules (e.g. if they are enabled or not).</td></tr><tr><td class="line">417</td><td class="hits"></td><td class="source"> * If they are switching (e.g. enabled &gt; disabled) it will run the disable hook.</td></tr><tr><td class="line">418</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">419</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">420</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">421</td><td class="hits">1</td><td class="source">function loadModules(next) {</td></tr><tr><td class="line">422</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">423</td><td class="hits">2</td><td class="source">  var configuredModules = calipso.config.get('modules') || {};</td></tr><tr><td class="line">424</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">425</td><td class="hits"></td><td class="source">  // Run any disable hooks</td></tr><tr class="hit"><td class="line">426</td><td class="hits">2</td><td class="source">  for (var module in calipso.modules) {</td></tr><tr><td class="line">427</td><td class="hits"></td><td class="source">    // Check to see if the module is currently enabled, if we are disabling it.</td></tr><tr class="hit"><td class="line">428</td><td class="hits">4</td><td class="source">    if (calipso.modules[module].enabled &amp;&amp; configuredModules[module].enabled === false &amp;&amp; typeof calipso.modules[module].fn.disable === 'function') {</td></tr><tr class="miss"><td class="line">429</td><td class="hits">0</td><td class="source">      calipso.modules[module].fn.disable();</td></tr><tr><td class="line">430</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">431</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">432</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">433</td><td class="hits"></td><td class="source">  // Clear the modules object (not sure if this is required, but was getting strange errors initially)</td></tr><tr class="hit"><td class="line">434</td><td class="hits">2</td><td class="source">  delete calipso.modules; // 'Delete' it.</td></tr><tr class="hit"><td class="line">435</td><td class="hits">2</td><td class="source">  calipso.modules = {}; // Always reset it</td></tr><tr><td class="line">436</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">437</td><td class="hits">2</td><td class="source">  var moduleBasePath = path.join(rootpath, calipso.config.get('server:modulePath'));</td></tr><tr><td class="line">438</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">439</td><td class="hits"></td><td class="source">  // Read the modules in from the file system, sync is fine as we do it once on load.</td></tr><tr class="hit"><td class="line">440</td><td class="hits">2</td><td class="source">  calipso.lib.fs.readdirSync(moduleBasePath).forEach(function(type) {</td></tr><tr><td class="line">441</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">442</td><td class="hits">2</td><td class="source">    if (type != &quot;README&quot; &amp;&amp; type != '.DS_Store') { // Ignore the readme file and .DS_Store file for Macs</td></tr><tr class="hit"><td class="line">443</td><td class="hits">2</td><td class="source">      calipso.lib.fs.readdirSync(path.join(moduleBasePath, type)).forEach(function(moduleFolderName) {</td></tr><tr><td class="line">444</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">445</td><td class="hits">8</td><td class="source">        if (moduleFolderName != &quot;README&quot; &amp;&amp; moduleFolderName != '.DS_Store') { // Ignore the readme file and .DS_Store file for Macs</td></tr><tr><td class="line">446</td><td class="hits"></td><td class="source">          </td></tr><tr class="hit"><td class="line">447</td><td class="hits">8</td><td class="source">          var modulePath = path.join(moduleBasePath, type, moduleFolderName);</td></tr><tr><td class="line">448</td><td class="hits"></td><td class="source">          </td></tr><tr class="hit"><td class="line">449</td><td class="hits">8</td><td class="source">          var module = {</td></tr><tr><td class="line">450</td><td class="hits"></td><td class="source">            name: moduleFolderName,</td></tr><tr><td class="line">451</td><td class="hits"></td><td class="source">            folder: moduleFolderName,</td></tr><tr><td class="line">452</td><td class="hits"></td><td class="source">            library: moduleFolderName,</td></tr><tr><td class="line">453</td><td class="hits"></td><td class="source">            type: type,</td></tr><tr><td class="line">454</td><td class="hits"></td><td class="source">            path: modulePath,</td></tr><tr><td class="line">455</td><td class="hits"></td><td class="source">            enabled: false,</td></tr><tr><td class="line">456</td><td class="hits"></td><td class="source">            inited: false</td></tr><tr><td class="line">457</td><td class="hits"></td><td class="source">          };</td></tr><tr><td class="line">458</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">459</td><td class="hits"></td><td class="source">          // Add about info to it</td></tr><tr class="hit"><td class="line">460</td><td class="hits">8</td><td class="source">          loadAbout(module, modulePath, 'package.json');</td></tr><tr><td class="line">461</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">462</td><td class="hits"></td><td class="source">          // Set the module name to what is in the package.json, default to folder name</td></tr><tr class="hit"><td class="line">463</td><td class="hits">8</td><td class="source">          module.name = module.about.name ? module.about.name : moduleFoldername;</td></tr><tr><td class="line">464</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">465</td><td class="hits"></td><td class="source">          // Now set the module</td></tr><tr class="hit"><td class="line">466</td><td class="hits">8</td><td class="source">          calipso.modules[module.name] = module;</td></tr><tr><td class="line">467</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">468</td><td class="hits"></td><td class="source">          // Set if it is enabled or not</td></tr><tr class="hit"><td class="line">469</td><td class="hits">8</td><td class="source">          module.enabled = configuredModules[module.name] ? configuredModules[module.name].enabled : false;</td></tr><tr><td class="line">470</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">471</td><td class="hits">8</td><td class="source">          if (module.enabled) {</td></tr><tr><td class="line">472</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">473</td><td class="hits"></td><td class="source">            // Load the module itself via require</td></tr><tr class="hit"><td class="line">474</td><td class="hits">8</td><td class="source">            requireModule(calipso.modules[module.name], modulePath);</td></tr><tr><td class="line">475</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">476</td><td class="hits"></td><td class="source">            // Load the templates (factored out so it can be recalled by watcher)</td></tr><tr class="hit"><td class="line">477</td><td class="hits">8</td><td class="source">            loadModuleTemplates(calipso.modules[module.name], path.join(modulePath,'templates'));</td></tr><tr><td class="line">478</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">479</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">480</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">481</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">482</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">483</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">484</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">485</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">486</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">487</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">488</td><td class="hits"></td><td class="source">  // Now that all are loaded, attach events &amp; depends</td></tr><tr class="hit"><td class="line">489</td><td class="hits">2</td><td class="source">  attachModuleEventsAndDependencies();</td></tr><tr><td class="line">490</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">491</td><td class="hits"></td><td class="source">  // Save configuration changes (if required)</td></tr><tr class="hit"><td class="line">492</td><td class="hits">2</td><td class="source">  if (calipso.config.dirty) {</td></tr><tr class="miss"><td class="line">493</td><td class="hits">0</td><td class="source">    calipso.config.save(next);</td></tr><tr><td class="line">494</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="hit"><td class="line">495</td><td class="hits">2</td><td class="source">    return next();</td></tr><tr><td class="line">496</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">497</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">498</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">499</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">500</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">501</td><td class="hits"></td><td class="source"> * Load data from package.json or theme.json</td></tr><tr><td class="line">502</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">503</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">504</td><td class="hits">1</td><td class="source">function loadAbout(obj, fromPath, file) {</td></tr><tr><td class="line">505</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">506</td><td class="hits">11</td><td class="source">  var fs = calipso.lib.fs;</td></tr><tr><td class="line">507</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">508</td><td class="hits">11</td><td class="source">  var packageFile = calipso.lib.path.join(fromPath, file);</td></tr><tr><td class="line">509</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">510</td><td class="hits">11</td><td class="source">  if (path.existsSync(packageFile)) {</td></tr><tr class="hit"><td class="line">511</td><td class="hits">11</td><td class="source">    var json = fs.readFileSync(packageFile);</td></tr><tr class="hit"><td class="line">512</td><td class="hits">11</td><td class="source">    try {</td></tr><tr class="hit"><td class="line">513</td><td class="hits">11</td><td class="source">      obj.about = JSON.parse(json.toString());</td></tr><tr class="hit"><td class="line">514</td><td class="hits">11</td><td class="source">      if (obj.about &amp;&amp; obj.about.name) {</td></tr><tr class="hit"><td class="line">515</td><td class="hits">11</td><td class="source">        obj.library = obj.about.name;</td></tr><tr><td class="line">516</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">517</td><td class="hits">0</td><td class="source">        obj.library = obj.name;</td></tr><tr><td class="line">518</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">519</td><td class="hits"></td><td class="source">    } catch (ex) {</td></tr><tr class="miss"><td class="line">520</td><td class="hits">0</td><td class="source">      obj.about = {</td></tr><tr><td class="line">521</td><td class="hits"></td><td class="source">        description: 'Invalid ' + file</td></tr><tr><td class="line">522</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">523</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">524</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">525</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">526</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">527</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">528</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">529</td><td class="hits"></td><td class="source"> * Connect up events and dependencies</td></tr><tr><td class="line">530</td><td class="hits"></td><td class="source"> * Must come after all modules are loaded</td></tr><tr><td class="line">531</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">532</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">533</td><td class="hits">1</td><td class="source">function attachModuleEventsAndDependencies() {</td></tr><tr><td class="line">534</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">535</td><td class="hits">2</td><td class="source">  var options = {maxListeners: calipso.config.get('server:events:maxListeners'), notifyDependencyFn: notifyDependenciesOfInit};</td></tr><tr><td class="line">536</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">537</td><td class="hits">2</td><td class="source">  for (var module in calipso.modules) {</td></tr><tr><td class="line">538</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">539</td><td class="hits"></td><td class="source">    // Register dependencies</td></tr><tr class="hit"><td class="line">540</td><td class="hits">8</td><td class="source">    registerModuleDependencies(calipso.modules[module]);</td></tr><tr><td class="line">541</td><td class="hits"></td><td class="source">    </td></tr><tr><td class="line">542</td><td class="hits"></td><td class="source">    // Attach event listener</td></tr><tr class="hit"><td class="line">543</td><td class="hits">8</td><td class="source">    calipso.event.addModuleEventListener(calipso.modules[module], options);</td></tr><tr><td class="line">544</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">545</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">546</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">547</td><td class="hits"></td><td class="source">  // Sweep through the dependency tree and make sure any broken dependencies are disabled</td></tr><tr class="hit"><td class="line">548</td><td class="hits">2</td><td class="source">  disableBrokenDependencies();</td></tr><tr><td class="line">549</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">550</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">551</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">552</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">553</td><td class="hits"></td><td class="source"> * Ensure dependencies are mapped and registered against parent and child</td></tr><tr><td class="line">554</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">555</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">556</td><td class="hits">1</td><td class="source">function registerModuleDependencies(module) {</td></tr><tr><td class="line">557</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">558</td><td class="hits">8</td><td class="source">  if (module.fn &amp;&amp; module.fn.depends &amp;&amp; module.enabled) {</td></tr><tr><td class="line">559</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">560</td><td class="hits"></td><td class="source">    // Create object to hold dependent status</td></tr><tr class="hit"><td class="line">561</td><td class="hits">2</td><td class="source">    module.check = {};</td></tr><tr><td class="line">562</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">563</td><td class="hits"></td><td class="source">    // Register depends on parent</td></tr><tr class="hit"><td class="line">564</td><td class="hits">2</td><td class="source">    module.fn.depends.forEach(function(dependentModule) {</td></tr><tr><td class="line">565</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">566</td><td class="hits">2</td><td class="source">      module.check[dependentModule] = false;</td></tr><tr><td class="line">567</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">568</td><td class="hits">2</td><td class="source">      if (calipso.modules[dependentModule] &amp;&amp; calipso.modules[dependentModule].enabled) {</td></tr><tr><td class="line">569</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">570</td><td class="hits"></td><td class="source">        // Create a notification array to allow this module to notify modules that depend on it</td></tr><tr class="hit"><td class="line">571</td><td class="hits">2</td><td class="source">        calipso.modules[dependentModule].notify = calipso.modules[dependentModule].notify || [];</td></tr><tr class="hit"><td class="line">572</td><td class="hits">2</td><td class="source">        calipso.modules[dependentModule].notify.push(module.name);</td></tr><tr><td class="line">573</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">574</td><td class="hits"></td><td class="source">      } else {</td></tr><tr><td class="line">575</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">576</td><td class="hits">0</td><td class="source">        calipso.modules[module.name].error = &quot;Module &quot; + module.name + &quot; depends on &quot; + dependentModule + &quot;, but it does not exist or is disabled - this module will not load.&quot;;</td></tr><tr class="miss"><td class="line">577</td><td class="hits">0</td><td class="source">        calipso.error(calipso.modules[module.name].error);</td></tr><tr class="miss"><td class="line">578</td><td class="hits">0</td><td class="source">        calipso.modules[module.name].enabled = false;</td></tr><tr><td class="line">579</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">580</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">581</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">582</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">583</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">584</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">585</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">586</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">587</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">588</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">589</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">590</td><td class="hits"></td><td class="source"> * Disable everythign in a broken dependency tree</td></tr><tr><td class="line">591</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">592</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">593</td><td class="hits">1</td><td class="source">function disableBrokenDependencies() {</td></tr><tr><td class="line">594</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">595</td><td class="hits">2</td><td class="source">  var disabled = 0;</td></tr><tr class="hit"><td class="line">596</td><td class="hits">2</td><td class="source">  for (var moduleName in calipso.modules) {</td></tr><tr class="hit"><td class="line">597</td><td class="hits">8</td><td class="source">    var module = calipso.modules[moduleName];</td></tr><tr class="hit"><td class="line">598</td><td class="hits">8</td><td class="source">    if (module.enabled &amp;&amp; module.fn &amp;&amp; module.fn.depends) {</td></tr><tr class="hit"><td class="line">599</td><td class="hits">2</td><td class="source">      module.fn.depends.forEach(function(dependentModule) {</td></tr><tr class="hit"><td class="line">600</td><td class="hits">2</td><td class="source">        if (!calipso.modules[dependentModule].enabled) {</td></tr><tr class="miss"><td class="line">601</td><td class="hits">0</td><td class="source">          calipso.modules[module.name].error = &quot;Module &quot; + module.name + &quot; depends on &quot; + dependentModule + &quot;, but it does not exist or is disabled - this module will not load.&quot;;</td></tr><tr class="miss"><td class="line">602</td><td class="hits">0</td><td class="source">          calipso.error(calipso.modules[module.name].error);</td></tr><tr class="miss"><td class="line">603</td><td class="hits">0</td><td class="source">          calipso.modules[module.name].enabled = false;</td></tr><tr class="miss"><td class="line">604</td><td class="hits">0</td><td class="source">          disabled = disabled + 1;</td></tr><tr><td class="line">605</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">606</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">607</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">608</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">609</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">610</td><td class="hits"></td><td class="source">  // Recursive</td></tr><tr class="hit"><td class="line">611</td><td class="hits">2</td><td class="source">  if (disabled &gt; 0) disableBrokenDependencies();</td></tr><tr><td class="line">612</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">613</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">614</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">615</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">616</td><td class="hits"></td><td class="source"> * Notify dependencies for initialisation</td></tr><tr><td class="line">617</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">618</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">619</td><td class="hits">1</td><td class="source">function notifyDependenciesOfInit(moduleName, options) {</td></tr><tr><td class="line">620</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">621</td><td class="hits">8</td><td class="source">  var module = calipso.modules[moduleName];</td></tr><tr class="hit"><td class="line">622</td><td class="hits">8</td><td class="source">  if (module.notify) {</td></tr><tr class="hit"><td class="line">623</td><td class="hits">2</td><td class="source">    module.notify.forEach(function(notifyModuleName) {</td></tr><tr class="hit"><td class="line">624</td><td class="hits">2</td><td class="source">      notifyDependencyOfInit(moduleName, notifyModuleName, options);</td></tr><tr><td class="line">625</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">626</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">627</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">628</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">629</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">630</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">631</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">632</td><td class="hits"></td><td class="source"> * Notify dependencies for routing</td></tr><tr><td class="line">633</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">634</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">635</td><td class="hits">1</td><td class="source">function notifyDependenciesOfRoute(req, res, moduleName, reqModules) {</td></tr><tr><td class="line">636</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">637</td><td class="hits">8</td><td class="source">  var module = calipso.modules[moduleName];</td></tr><tr class="hit"><td class="line">638</td><td class="hits">8</td><td class="source">  if (module.notify) {</td></tr><tr class="hit"><td class="line">639</td><td class="hits">4</td><td class="source">    module.notify.forEach(function(notifyModuleName) {</td></tr><tr class="hit"><td class="line">640</td><td class="hits">4</td><td class="source">      notifyDependencyOfRoute(req, res, moduleName, notifyModuleName);</td></tr><tr><td class="line">641</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">642</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">643</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">644</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">645</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">646</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">647</td><td class="hits"></td><td class="source"> * Notify dependency</td></tr><tr><td class="line">648</td><td class="hits"></td><td class="source"> * moduleName - module that has init'd</td></tr><tr><td class="line">649</td><td class="hits"></td><td class="source"> * notifyModuleName - module to tell</td></tr><tr><td class="line">650</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">651</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">652</td><td class="hits">1</td><td class="source">function notifyDependencyOfInit(moduleName, notifyModuleName, options) {</td></tr><tr><td class="line">653</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">654</td><td class="hits"></td><td class="source">  // Set it to true</td></tr><tr class="hit"><td class="line">655</td><td class="hits">2</td><td class="source">  var module = calipso.modules[notifyModuleName];</td></tr><tr class="hit"><td class="line">656</td><td class="hits">2</td><td class="source">  module.check[moduleName] = true;</td></tr><tr class="hit"><td class="line">657</td><td class="hits">2</td><td class="source">  checkInit(module);</td></tr><tr><td class="line">658</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">659</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">660</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">661</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">662</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">663</td><td class="hits"></td><td class="source"> * Notify dependency</td></tr><tr><td class="line">664</td><td class="hits"></td><td class="source"> * req - request</td></tr><tr><td class="line">665</td><td class="hits"></td><td class="source"> * res - response</td></tr><tr><td class="line">666</td><td class="hits"></td><td class="source"> * moduleName - module that has init'd</td></tr><tr><td class="line">667</td><td class="hits"></td><td class="source"> * notifyModuleName - module to tell</td></tr><tr><td class="line">668</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">669</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">670</td><td class="hits">1</td><td class="source">function notifyDependencyOfRoute(req, res, moduleName, notifyModuleName) {</td></tr><tr><td class="line">671</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">672</td><td class="hits">4</td><td class="source">  var module = req.event.modules[notifyModuleName];</td></tr><tr class="hit"><td class="line">673</td><td class="hits">4</td><td class="source">  module.check[moduleName] = true;</td></tr><tr class="hit"><td class="line">674</td><td class="hits">4</td><td class="source">  checkRouted(req, res, moduleName, notifyModuleName);</td></tr><tr><td class="line">675</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">676</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">677</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">678</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">679</td><td class="hits"></td><td class="source"> * Check if all dependencies are met and we should init the module</td></tr><tr><td class="line">680</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">681</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">682</td><td class="hits">1</td><td class="source">function checkInit(module, next) {</td></tr><tr><td class="line">683</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">684</td><td class="hits">2</td><td class="source">  var doInit = true;</td></tr><tr class="hit"><td class="line">685</td><td class="hits">2</td><td class="source">  for (var check in module.check) {</td></tr><tr class="hit"><td class="line">686</td><td class="hits">2</td><td class="source">    doInit = doInit &amp; module.check[check];</td></tr><tr><td class="line">687</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">688</td><td class="hits">2</td><td class="source">  if (doInit) {</td></tr><tr><td class="line">689</td><td class="hits"></td><td class="source">    // Initiate the module, no req for callback</td></tr><tr class="hit"><td class="line">690</td><td class="hits">2</td><td class="source">    initModule(module.name, true, function() {});</td></tr><tr><td class="line">691</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">692</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">693</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">694</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">695</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">696</td><td class="hits"></td><td class="source"> * Check if all dependencies are met and we should route the module</td></tr><tr><td class="line">697</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">698</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">699</td><td class="hits">1</td><td class="source">function checkRouted(req, res, moduleName, notifyModuleName) {</td></tr><tr><td class="line">700</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">701</td><td class="hits">4</td><td class="source">  var doRoute = true;</td></tr><tr><td class="line">702</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">703</td><td class="hits">4</td><td class="source">  for (var check in req.event.modules[notifyModuleName].check) {</td></tr><tr class="hit"><td class="line">704</td><td class="hits">4</td><td class="source">    doRoute = doRoute &amp;&amp; req.event.modules[notifyModuleName].check[check];</td></tr><tr><td class="line">705</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">706</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">707</td><td class="hits">4</td><td class="source">  if (doRoute) {</td></tr><tr><td class="line">708</td><td class="hits"></td><td class="source">    // Initiate the module, no req for callback</td></tr><tr><td class="line">709</td><td class="hits"></td><td class="source">    // initModule(module.name,true,function() {});</td></tr><tr class="hit"><td class="line">710</td><td class="hits">4</td><td class="source">    routeModule(req, res, notifyModuleName, true, false, function() {});</td></tr><tr><td class="line">711</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">712</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">713</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">714</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">715</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">716</td><td class="hits"></td><td class="source"> * Load the module itself, refactored out to enable watch / reload</td></tr><tr><td class="line">717</td><td class="hits"></td><td class="source"> * Note, while it was refactored out, you can't currently reload</td></tr><tr><td class="line">718</td><td class="hits"></td><td class="source"> * a module, will patch in node-supervisor to watch the js files and restart</td></tr><tr><td class="line">719</td><td class="hits"></td><td class="source"> * the whole server (only option :())</td></tr><tr><td class="line">720</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">721</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">722</td><td class="hits">1</td><td class="source">function requireModule(module, modulePath, reload, next) {</td></tr><tr><td class="line">723</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">724</td><td class="hits">8</td><td class="source">  var fs = calipso.lib.fs;</td></tr><tr class="hit"><td class="line">725</td><td class="hits">8</td><td class="source">  var moduleFile = path.join(modulePath + '/' + module.name);</td></tr><tr><td class="line">726</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">727</td><td class="hits">8</td><td class="source">  try {</td></tr><tr><td class="line">728</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">729</td><td class="hits"></td><td class="source">    // Require the module</td></tr><tr class="hit"><td class="line">730</td><td class="hits">8</td><td class="source">    module.fn = require(moduleFile);</td></tr><tr><td class="line">731</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">732</td><td class="hits"></td><td class="source">    // Attach a router - legacy check for default routes</td></tr><tr class="hit"><td class="line">733</td><td class="hits">8</td><td class="source">    module.router = new calipso.router(module.name, modulePath);</td></tr><tr><td class="line">734</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">735</td><td class="hits"></td><td class="source">    // Load the routes if specified as either array or function</td></tr><tr class="hit"><td class="line">736</td><td class="hits">8</td><td class="source">    if (typeof module.fn.routes === &quot;function&quot;) module.fn.routes = module.fn.routes();</td></tr><tr class="hit"><td class="line">737</td><td class="hits">8</td><td class="source">    module.fn.routes = module.fn.routes || [];</td></tr><tr><td class="line">738</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">739</td><td class="hits"></td><td class="source">    // Ensure the defaultConfig exists (e.g. if it hasn't been required before)</td></tr><tr><td class="line">740</td><td class="hits"></td><td class="source">    // This is saved in the wider loadModules loop to ensure only one config save action (if required)</td></tr><tr class="hit"><td class="line">741</td><td class="hits">8</td><td class="source">    if (module.fn.config &amp;&amp; !calipso.config.getModuleConfig(module.name, '')) {</td></tr><tr class="miss"><td class="line">742</td><td class="hits">0</td><td class="source">      calipso.config.setDefaultModuleConfig(module.name, module.fn.config);</td></tr><tr><td class="line">743</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">744</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">745</td><td class="hits"></td><td class="source">  } catch (ex) {</td></tr><tr><td class="line">746</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">747</td><td class="hits">0</td><td class="source">    calipso.error(&quot;Module &quot; + module.name + &quot; has been disabled because &quot; + ex.message);</td></tr><tr class="miss"><td class="line">748</td><td class="hits">0</td><td class="source">    calipso.modules[module.name].enabled = false;</td></tr><tr><td class="line">749</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">750</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">751</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">752</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">753</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">754</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">755</td><td class="hits"></td><td class="source"> * Pre load all the templates in a module, synch, but only happens on app start up and config reload</td></tr><tr><td class="line">756</td><td class="hits"></td><td class="source"> * This is attached to the templates attribute so used later.</td></tr><tr><td class="line">757</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">758</td><td class="hits"></td><td class="source"> * @param calipso</td></tr><tr><td class="line">759</td><td class="hits"></td><td class="source"> * @param moduleTemplatePath</td></tr><tr><td class="line">760</td><td class="hits"></td><td class="source"> * @returns template object</td></tr><tr><td class="line">761</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">762</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">763</td><td class="hits">1</td><td class="source">function loadModuleTemplates(module, moduleTemplatePath) {</td></tr><tr><td class="line">764</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">765</td><td class="hits">8</td><td class="source">  var templates = {};</td></tr><tr><td class="line">766</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">767</td><td class="hits"></td><td class="source">  // Default the template to any loaded in the theme (overrides)</td></tr><tr class="hit"><td class="line">768</td><td class="hits">8</td><td class="source">  var fs = calipso.lib.fs;</td></tr><tr><td class="line">769</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">770</td><td class="hits">8</td><td class="source">  if (!calipso.lib.path.existsSync(moduleTemplatePath)) {</td></tr><tr class="hit"><td class="line">771</td><td class="hits">6</td><td class="source">    return null;</td></tr><tr><td class="line">772</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">773</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">774</td><td class="hits">2</td><td class="source">  fs.readdirSync(moduleTemplatePath).forEach(function(name) {</td></tr><tr><td class="line">775</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">776</td><td class="hits"></td><td class="source">    // Template paths and functions</td></tr><tr class="hit"><td class="line">777</td><td class="hits">2</td><td class="source">    var templatePath = moduleTemplatePath + &quot;/&quot; + name;</td></tr><tr class="hit"><td class="line">778</td><td class="hits">2</td><td class="source">    var templateExtension = templatePath.match(/([^\.]+)$/)[0];</td></tr><tr class="hit"><td class="line">779</td><td class="hits">2</td><td class="source">    var template = fs.readFileSync(templatePath, 'utf8');</td></tr><tr class="hit"><td class="line">780</td><td class="hits">2</td><td class="source">    var templateName = name.replace(/\.([^\.]+)$/, '');</td></tr><tr><td class="line">781</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">782</td><td class="hits"></td><td class="source">    // Load the template - only if not already loaded by theme (e.g. overriden)</td></tr><tr class="hit"><td class="line">783</td><td class="hits">2</td><td class="source">    var hasTemplate = calipso.utils.hasProperty('theme.cache.modules.' + module.name + '.templates.' + templateName, calipso);</td></tr><tr><td class="line">784</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">785</td><td class="hits">2</td><td class="source">    if (hasTemplate) {</td></tr><tr><td class="line">786</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">787</td><td class="hits"></td><td class="source">      // Use the theme version</td></tr><tr class="miss"><td class="line">788</td><td class="hits">0</td><td class="source">      templates[templateName] = calipso.theme.cache.modules[module.name].templates[templateName];</td></tr><tr><td class="line">789</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">790</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">791</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">792</td><td class="hits"></td><td class="source">      // Else load it</td></tr><tr class="hit"><td class="line">793</td><td class="hits">2</td><td class="source">      if (template) {</td></tr><tr><td class="line">794</td><td class="hits"></td><td class="source">        // calipso.theme.compileTemplate =&gt; ./Theme.js</td></tr><tr class="hit"><td class="line">795</td><td class="hits">2</td><td class="source">        templates[templateName] = calipso.theme.compileTemplate(template, templatePath, templateExtension);</td></tr><tr><td class="line">796</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">797</td><td class="hits"></td><td class="source">        // Watch / unwatch files - always unwatch (e.g. around config changes)</td></tr><tr class="hit"><td class="line">798</td><td class="hits">2</td><td class="source">        if (calipso.config.get('performance:watchFiles')) {</td></tr><tr><td class="line">799</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">800</td><td class="hits">2</td><td class="source">          fs.unwatchFile(templatePath); // Always unwatch first due to recursive behaviour</td></tr><tr class="hit"><td class="line">801</td><td class="hits">2</td><td class="source">          fs.watchFile(templatePath, {</td></tr><tr><td class="line">802</td><td class="hits"></td><td class="source">            persistent: true,</td></tr><tr><td class="line">803</td><td class="hits"></td><td class="source">            interval: 200</td></tr><tr><td class="line">804</td><td class="hits"></td><td class="source">          }, function(curr, prev) {</td></tr><tr class="miss"><td class="line">805</td><td class="hits">0</td><td class="source">            loadModuleTemplates(module, moduleTemplatePath);</td></tr><tr class="miss"><td class="line">806</td><td class="hits">0</td><td class="source">            calipso.silly(&quot;Module &quot; + module.name + &quot; template &quot; + name + &quot; reloaded.&quot;);</td></tr><tr><td class="line">807</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">808</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">809</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">810</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">811</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">812</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">813</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">814</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">815</td><td class="hits">2</td><td class="source">  module.templates = templates;</td></tr><tr><td class="line">816</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">817</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">818</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">819</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">820</td><td class="hits"></td><td class="source"> *  Exports</td></tr><tr><td class="line">821</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">822</td><td class="hits">1</td><td class="source">module.exports = {</td></tr><tr><td class="line">823</td><td class="hits"></td><td class="source">  loadModules: loadModules,</td></tr><tr><td class="line">824</td><td class="hits"></td><td class="source">  initModules: initModules,</td></tr><tr><td class="line">825</td><td class="hits"></td><td class="source">  eventRouteModules: eventRouteModules,</td></tr><tr><td class="line">826</td><td class="hits"></td><td class="source">  notifyDependenciesOfInit: notifyDependenciesOfInit,</td></tr><tr><td class="line">827</td><td class="hits"></td><td class="source">  notifyDependenciesOfRoute: notifyDependenciesOfRoute,</td></tr><tr><td class="line">828</td><td class="hits"></td><td class="source">  registerDependencies: registerDependencies,</td></tr><tr><td class="line">829</td><td class="hits"></td><td class="source">  loadAbout: loadAbout</td></tr><tr><td class="line">830</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/Permission.js">core/Permission.js</h2><div id="stats" class="medium"><div class="percentage">55%</div><div class="sloc">60</div><div class="hits">33</div><div class="misses">27</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Permissions Class</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * This library adds a permissions class to the router, defining functions that are used by the router to control access.</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">10</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * A set of helper functions to simplify the application of filters, as well as store</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * the in memory map of roles to permissions (in memory for performance reasons)</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">var PermissionHelpers = {</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">  // Holder of defined permissions</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">  permissions: {},</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">  sortedPermissions: [],</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">  structuredPermissions: {},</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source">  // Clear all oaded permissions</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">  clearPermissionRoles: function() {</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">28</td><td class="hits">0</td><td class="source">    var self = this;</td></tr><tr class="miss"><td class="line">29</td><td class="hits">0</td><td class="source">    for (var perm in self.permissions) {</td></tr><tr class="miss"><td class="line">30</td><td class="hits">0</td><td class="source">      delete self.permissions[perm].roles;</td></tr><tr class="miss"><td class="line">31</td><td class="hits">0</td><td class="source">      self.permissions[perm].roles = [];</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  // Add a permission</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">  addPermission: function(permission, description, isCrud) {</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">39</td><td class="hits">1</td><td class="source">    var self = this;</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">    // if Crud, automatically add level below</td></tr><tr class="hit"><td class="line">42</td><td class="hits">1</td><td class="source">    if (isCrud) {</td></tr><tr class="miss"><td class="line">43</td><td class="hits">0</td><td class="source">      calipso.lib._.map([&quot;view&quot;, &quot;create&quot;, &quot;update&quot;, &quot;delete&quot;], function(crudAction) {</td></tr><tr class="miss"><td class="line">44</td><td class="hits">0</td><td class="source">        var crudPermission = permission + &quot;:&quot; + crudAction;</td></tr><tr class="miss"><td class="line">45</td><td class="hits">0</td><td class="source">        self.permissions[crudPermission] = {</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">          roles: [],</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">          queries: [],</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">          description: crudAction + &quot; &quot; + description</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">        };</td></tr><tr class="miss"><td class="line">50</td><td class="hits">0</td><td class="source">        self.sortedPermissions.push(crudPermission);</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">      // Add Permission always resets it if it already exists</td></tr><tr class="hit"><td class="line">55</td><td class="hits">1</td><td class="source">      self.permissions[permission] = {</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">        roles: [],</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">        queries: [],</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">        description: description</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">      };</td></tr><tr class="hit"><td class="line">60</td><td class="hits">1</td><td class="source">      self.sortedPermissions.push(permission);</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">  structureAndSort: function() {</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">68</td><td class="hits">0</td><td class="source">    var self = this;</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">    // This could be done by the permissions module</td></tr><tr class="miss"><td class="line">71</td><td class="hits">0</td><td class="source">    self.sortedPermissions.sort(function(a, b) {</td></tr><tr class="miss"><td class="line">72</td><td class="hits">0</td><td class="source">      return a &lt; b;</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">    // Now we need to create our permissions object structure</td></tr><tr class="miss"><td class="line">76</td><td class="hits">0</td><td class="source">    self.sortedPermissions.forEach(function(value) {</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">78</td><td class="hits">0</td><td class="source">      var path = value.split(&quot;:&quot;),</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source">        target = self.structuredPermissions,</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">        counter = 0;</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">82</td><td class="hits">0</td><td class="source">      while (path.length &gt; 1) {</td></tr><tr class="miss"><td class="line">83</td><td class="hits">0</td><td class="source">        key = path.shift();</td></tr><tr class="miss"><td class="line">84</td><td class="hits">0</td><td class="source">        if (!target[key] || typeof target[key] !== 'object') {</td></tr><tr class="miss"><td class="line">85</td><td class="hits">0</td><td class="source">          target[key] = {};</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">        }</td></tr><tr class="miss"><td class="line">87</td><td class="hits">0</td><td class="source">        target = target[key];</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">      // Set the specified value in the nested JSON structure</td></tr><tr class="miss"><td class="line">91</td><td class="hits">0</td><td class="source">      key = path.shift();</td></tr><tr class="miss"><td class="line">92</td><td class="hits">0</td><td class="source">      if (typeof target[key] !== &quot;object&quot;) {</td></tr><tr class="miss"><td class="line">93</td><td class="hits">0</td><td class="source">        target[key] = self.permissions[value].roles;</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">  // Add a map between role / permission (this is loaded via the user module)</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">  addPermissionRole: function(permission, role) {</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">103</td><td class="hits">1</td><td class="source">    var self = this;</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source">    // Store this as a simple in memory map</td></tr><tr class="hit"><td class="line">106</td><td class="hits">1</td><td class="source">    if (self.permissions[permission]) {</td></tr><tr class="hit"><td class="line">107</td><td class="hits">1</td><td class="source">      self.permissions[permission].roles.push(role);</td></tr><tr class="hit"><td class="line">108</td><td class="hits">1</td><td class="source">      return true;</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">110</td><td class="hits">0</td><td class="source">      calipso.warn(&quot;Attempted to map role: &quot; + role + &quot; to a permission: &quot; + permission + &quot; that does not exist (perhaps related to a disabled module?).&quot;);</td></tr><tr class="miss"><td class="line">111</td><td class="hits">0</td><td class="source">      return false;</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">  // Does a user have a role</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source">  hasRole: function(role) {</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source">    // Curried filter</td></tr><tr class="miss"><td class="line">119</td><td class="hits">0</td><td class="source">    return function(user) {</td></tr><tr class="miss"><td class="line">120</td><td class="hits">0</td><td class="source">      var isAllowed = user.roles.indexOf(role) &gt;= 0 ? true : false,</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">        message = isAllowed ? ('User has role ' + role) : 'You dont have the appropriate roles to view that page!';</td></tr><tr class="miss"><td class="line">122</td><td class="hits">0</td><td class="source">      return {</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source">        allow: isAllowed,</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">        msg: message</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">  // Does a user have a permission</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">  hasPermission: function(permission) {</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">132</td><td class="hits">3</td><td class="source">    var self = this;</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source">    // Curried filter</td></tr><tr class="hit"><td class="line">135</td><td class="hits">3</td><td class="source">    return function(user) {</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">      // Check if the user has a role that maps to the permission</td></tr><tr class="hit"><td class="line">138</td><td class="hits">26</td><td class="source">      var userRoles = user.roles,</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">          permissionRoles = self.permissions[permission] ? self.permissions[permission].roles : [];</td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">      // Check if allowed based on intersection of user roles and roles that have permission</td></tr><tr class="hit"><td class="line">142</td><td class="hits">26</td><td class="source">      var isAllowed = calipso.lib._.intersect(permissionRoles, userRoles).length &gt; 0,</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">        message = isAllowed ? ('User has permission ' + permission) : 'You do not have any of the roles required to perform that action.';</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">146</td><td class="hits">26</td><td class="source">      return {</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">        allow: isAllowed,</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">        msg: message</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source"> * The default calipso permission filter, this is attached to every route, and processed as part of the route matching.</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">161</td><td class="hits">1</td><td class="source">function PermissionFilter(options, permit) {</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">  // Store the options</td></tr><tr class="hit"><td class="line">164</td><td class="hits">36</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">165</td><td class="hits">36</td><td class="source">  self.options = options;</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">167</td><td class="hits">36</td><td class="source">  if(permit) {</td></tr><tr class="hit"><td class="line">168</td><td class="hits">30</td><td class="source">    if(typeof permit === 'function') {</td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">      // permit is already a fn created by a helper</td></tr><tr class="hit"><td class="line">170</td><td class="hits">28</td><td class="source">      self.permit = permit;</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">      // permit is a string - e.g. 'admin:core:configuration'</td></tr><tr class="hit"><td class="line">173</td><td class="hits">2</td><td class="source">      self.permit = calipso.permission.Helper.hasPermission(permit);</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">179</td><td class="hits">1</td><td class="source">PermissionFilter.prototype.check = function(req) {</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">181</td><td class="hits">30</td><td class="source">  var self = this;</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">183</td><td class="hits">30</td><td class="source">  if (self.permit) {</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">185</td><td class="hits">30</td><td class="source">    var user = req.session.user;</td></tr><tr class="hit"><td class="line">186</td><td class="hits">30</td><td class="source">    var isAdmin = req.session.user &amp;&amp; req.session.user.isAdmin;</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">188</td><td class="hits">32</td><td class="source">    if (isAdmin) return {</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source">      allow: true</td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">    }; // Admins always access everything</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source">    // Else check for a specific permission</td></tr><tr class="hit"><td class="line">192</td><td class="hits">28</td><td class="source">    if (user) {</td></tr><tr class="hit"><td class="line">193</td><td class="hits">26</td><td class="source">      return self.permit(user);</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">195</td><td class="hits">2</td><td class="source">      return {</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">        allow: false,</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">        msg: 'You must be a logged in user to view that page'</td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="miss"><td class="line">202</td><td class="hits">0</td><td class="source">    return {</td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">      allow: true</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source"> * Export an instance of our object</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">213</td><td class="hits">1</td><td class="source">exports.Filter = PermissionFilter;</td></tr><tr class="hit"><td class="line">214</td><td class="hits">1</td><td class="source">exports.Helper = PermissionHelpers;</td></tr></tbody></table></div><div class="file"><h2 id="core/Router.js">core/Router.js</h2><div id="stats" class="high"><div class="percentage">76%</div><div class="sloc">86</div><div class="hits">66</div><div class="misses">20</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso Core Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * The Calipso Router provides a router object to each module that enables each module to register</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * its own functions to respond to URL patterns (as per the typical Express approach).  Note</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * that Calipso itself does not respond to any URL outside of those exposed by a module, if all are disabled</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * the application will do nothing.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> * Borrowed liberally from Connect / ExpressJS itself for this, thanks for the great work!</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> * Includes</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">17</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">  url = require('url'),</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">  fs = require('fs'),</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">  PermissionFilter = require('./Permission').Filter,</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">  PermissionHelper = require('./Permission').Helper,</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">  blocks = require('./Blocks');</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> * Core router object, use the return model to ensure</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> * that we always return a new instance when called.</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> * A Router is attached to each module, and allows each module to effectively</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source"> * act as its own controller in a mini MVC model.</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> * This class exposes:</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> *     addRoutes: function, to add Routes to a module.</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> *     route: iterate through the routes, match, and then call the matched function in the module.</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">39</td><td class="hits">1</td><td class="source">var Router = function(moduleName, modulePath) {</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">41</td><td class="hits">8</td><td class="source">    return {</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">      moduleName: moduleName,</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">      modulePath: modulePath,</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">      routes: [],</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">      /**</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source">       * A route is defined by three parameters:</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">       *</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source">       * path:  a string in the form 'GET /url' where the first piece is the HTTP method to respond to.</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">       *        OR</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source">       *        a regex function (it matches only on GET requests).</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">       * fn:    the function in the module to call if the route matches.</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">       * options: additional configuration options, specifically:</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">       *    end - deprecated. TODO CLEANUP</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">       *    admin - is the route an administrative route (user must have isAdmin = true).</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">       */</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">      addRoute: function(options, next, legacy_options, legacy_next) {</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">        // Default options</td></tr><tr class="hit"><td class="line">61</td><td class="hits">8</td><td class="source">        var self = this,</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">          defaults = {</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">            end: true,</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">            admin: false,</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">            user: false,</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">            cache: false,</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source">            permit: null</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">          };</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">        // Deal with legacy, this will eventually just be options, next to enable simpler invocation</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">        // And to make it more extensible</td></tr><tr class="hit"><td class="line">72</td><td class="hits">8</td><td class="source">        if (typeof legacy_next === &quot;function&quot;) {</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">74</td><td class="hits">6</td><td class="source">          var routePath = options,</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">              fn = next;</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">          // Set the variables</td></tr><tr class="hit"><td class="line">78</td><td class="hits">6</td><td class="source">          options = legacy_options || {};</td></tr><tr class="hit"><td class="line">79</td><td class="hits">6</td><td class="source">          options.path = routePath;</td></tr><tr class="hit"><td class="line">80</td><td class="hits">6</td><td class="source">          options.fn = fn;</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">82</td><td class="hits">6</td><td class="source">          next = legacy_next;</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">84</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">        // Default options</td></tr><tr class="hit"><td class="line">87</td><td class="hits">8</td><td class="source">        options = calipso.lib._.extend(defaults, options);        </td></tr><tr class="hit"><td class="line">88</td><td class="hits">8</td><td class="source">        options.permitFn = new PermissionFilter(options, options.permit);</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">              </td></tr><tr class="hit"><td class="line">90</td><td class="hits">8</td><td class="source">        self.routes.push(options);</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">92</td><td class="hits">8</td><td class="source">        next();</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">      },</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">      /**</td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">       * Module routing function, iterates through the configured routes and trys to match.</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">       * This has been borrowed from the Express core routing module and refactored slightly</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source">       * to deal with the fact this is much more specific.</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">       */</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">      route: function(req, res, next) {</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">103</td><td class="hits">16</td><td class="source">        var self = this,</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">          requestUrl = url.parse(req.url, true),</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source">          routes = this.routes;</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">        // Use step to enable parallel execution</td></tr><tr class="hit"><td class="line">108</td><td class="hits">16</td><td class="source">        calipso.lib.step(</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">        function matchRoutes() {</td></tr><tr><td class="line">111</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">          // Emit event to indicate starting</td></tr><tr class="hit"><td class="line">113</td><td class="hits">16</td><td class="source">          var i, l, group = this.group();</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">115</td><td class="hits">16</td><td class="source">          for (i = 0, l = routes.length; i &lt; l; i = i + 1) {</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">117</td><td class="hits">16</td><td class="source">            var keys = [],</td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source">              route = routes[i],</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">              templateFn = null,</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">              block = &quot;&quot;,</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">              routeMethod = &quot;&quot;,</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source">              routeRegEx, j, paramLen, param, allPages = false;</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">124</td><td class="hits">16</td><td class="source">            if (typeof route.path === &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">125</td><td class="hits">8</td><td class="source">              routeMethod = route.path.split(&quot; &quot;)[0];</td></tr><tr class="hit"><td class="line">126</td><td class="hits">8</td><td class="source">              routeRegEx = normalizePath(route.path.split(&quot; &quot;)[1], keys);</td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">            } else {</td></tr><tr class="hit"><td class="line">128</td><td class="hits">8</td><td class="source">              routeRegEx = route.path;</td></tr><tr class="hit"><td class="line">129</td><td class="hits">8</td><td class="source">              allPages = true; // Is a regex</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">132</td><td class="hits">16</td><td class="source">            var captures = requestUrl.pathname.match(routeRegEx);</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">134</td><td class="hits">16</td><td class="source">            if (captures &amp;&amp; (!routeMethod || req.method === routeMethod)) {</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">              // Check to see if we matched a non /.*/ route to flag a 404 later</td></tr><tr class="hit"><td class="line">137</td><td class="hits">11</td><td class="source">              res.routeMatched = !allPages || res.routeMatched;</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source">              // If admin, then set the route</td></tr><tr class="hit"><td class="line">140</td><td class="hits">11</td><td class="source">              if (route.admin) {</td></tr><tr class="hit"><td class="line">141</td><td class="hits">2</td><td class="source">                res.layout = &quot;admin&quot;;</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source">              // TODO </td></tr><tr class="hit"><td class="line">145</td><td class="hits">11</td><td class="source">              var isAdmin = req.session.user &amp;&amp; req.session.user.isAdmin;</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">              // Check to see if it requires logged in user access</td></tr><tr class="hit"><td class="line">148</td><td class="hits">11</td><td class="source">              if (route.permit) {</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">150</td><td class="hits">2</td><td class="source">                var permit = route.permitFn.check(req);</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">152</td><td class="hits">2</td><td class="source">                if (typeof permit !== &quot;object&quot;) permit = {</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source">                  allow: false,</td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">                  msg: 'You don\'t have the appropriate permissions to view that page.'</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source">                };</td></tr><tr class="hit"><td class="line">156</td><td class="hits">2</td><td class="source">                if (!permit.allow) {</td></tr><tr class="hit"><td class="line">157</td><td class="hits">1</td><td class="source">                  if (!allPages) {</td></tr><tr class="hit"><td class="line">158</td><td class="hits">1</td><td class="source">                    req.flash('error', req.t(permit.msg));</td></tr><tr class="hit"><td class="line">159</td><td class="hits">1</td><td class="source">                    res.statusCode = 401;</td></tr><tr class="hit"><td class="line">160</td><td class="hits">1</td><td class="source">                    res.redirect(&quot;/&quot;);</td></tr><tr class="hit"><td class="line">161</td><td class="hits">1</td><td class="source">                    return group()();</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source">                  } else {</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">                    // Simply ignore silently</td></tr><tr class="miss"><td class="line">164</td><td class="hits">0</td><td class="source">                    return group()();</td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source">                  }</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">                }</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">              // Debugging - only when logged in as admin user</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source">              // calipso.silly(&quot;Module &quot; + router.moduleName + &quot; matched route: &quot; + requestUrl.pathname + &quot; / &quot; + routeRegEx.toString() + &quot; [&quot; + res.routeMatched + &quot;]&quot;);</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">              // Lookup the template for this route</td></tr><tr class="hit"><td class="line">172</td><td class="hits">10</td><td class="source">              if (route.template) {</td></tr><tr class="hit"><td class="line">173</td><td class="hits">1</td><td class="source">                templateFn = calipso.modules[self.moduleName].templates[route.template];</td></tr><tr class="hit"><td class="line">174</td><td class="hits">1</td><td class="source">                if (!templateFn &amp;&amp; route.template) {</td></tr><tr class="miss"><td class="line">175</td><td class="hits">0</td><td class="source">                  var err = new Error(&quot;The specified template: &quot; + route.template + &quot; does not exist in the module: &quot; + self.modulePath);</td></tr><tr class="miss"><td class="line">176</td><td class="hits">0</td><td class="source">                  return group()(err);</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">                } else {</td></tr><tr class="hit"><td class="line">178</td><td class="hits">1</td><td class="source">                  calipso.silly(&quot;Using template: &quot; + route.template + &quot; for module: &quot; + self.modulePath);</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">                }</td></tr><tr class="hit"><td class="line">180</td><td class="hits">1</td><td class="source">                route.templateFn = templateFn;</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">              // Set the object to hold the rendered blocks if it hasn't been created already</td></tr><tr class="hit"><td class="line">184</td><td class="hits">10</td><td class="source">              if (!res.renderedBlocks) {</td></tr><tr class="hit"><td class="line">185</td><td class="hits">1</td><td class="source">                res.renderedBlocks = new blocks.RenderedBlocks(calipso.cacheService);</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">              // Copy over any params that make sense from the url</td></tr><tr class="hit"><td class="line">189</td><td class="hits">10</td><td class="source">              req.moduleParams = {};</td></tr><tr class="hit"><td class="line">190</td><td class="hits">10</td><td class="source">              for (j = 1, paramLen = captures.length; j &lt; paramLen; j = j + 1) {</td></tr><tr class="miss"><td class="line">191</td><td class="hits">0</td><td class="source">                var key = keys[j - 1],</td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source">                  val = typeof captures[j] === 'string' ? decodeURIComponent(captures[j]) : captures[j];</td></tr><tr class="miss"><td class="line">193</td><td class="hits">0</td><td class="source">                if (key) {</td></tr><tr class="miss"><td class="line">194</td><td class="hits">0</td><td class="source">                  req.moduleParams[key] = val;</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">                } else {</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">                  // Comes from custom regex, no key</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">                  // req.moduleParams[&quot;regex&quot;] = val;</td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">                }</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">              // Convert any url parameters if we are not a .* match</td></tr><tr class="hit"><td class="line">202</td><td class="hits">10</td><td class="source">              if (requestUrl.query &amp;&amp; !allPages) {</td></tr><tr class="hit"><td class="line">203</td><td class="hits">2</td><td class="source">                for (param in requestUrl.query) {</td></tr><tr class="miss"><td class="line">204</td><td class="hits">0</td><td class="source">                  if (requestUrl.query.hasOwnProperty(param)) {</td></tr><tr class="miss"><td class="line">205</td><td class="hits">0</td><td class="source">                    req.moduleParams[param] = requestUrl.query[param];</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source">                  }</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">                }</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source">              // Store the params for use outside the router</td></tr><tr class="hit"><td class="line">211</td><td class="hits">10</td><td class="source">              res.params = res.params || {};</td></tr><tr class="hit"><td class="line">212</td><td class="hits">10</td><td class="source">              calipso.lib._.extend(res.params, req.moduleParams);</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">              // Set if we should cache this block - do not cache by default, do not cache admins</td></tr><tr class="hit"><td class="line">215</td><td class="hits">10</td><td class="source">              var cacheBlock = res.renderedBlocks.contentCache[block] = route.cache &amp;&amp; !isAdmin;</td></tr><tr class="hit"><td class="line">216</td><td class="hits">10</td><td class="source">              var cacheEnabled = calipso.config.get('performance:cache:enabled');</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">218</td><td class="hits">10</td><td class="source">              if (route.block &amp;&amp; cacheBlock &amp;&amp; cacheEnabled) {</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">220</td><td class="hits">0</td><td class="source">                var cacheKey = calipso.cacheService.getCacheKey(['block', route.block], res.params);</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">222</td><td class="hits">0</td><td class="source">                calipso.cacheService.check(cacheKey, function(err, isCached) {</td></tr><tr class="miss"><td class="line">223</td><td class="hits">0</td><td class="source">                  if (isCached) {</td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source">                    // Set the block from the cache, set layout if needed</td></tr><tr class="miss"><td class="line">225</td><td class="hits">0</td><td class="source">                    res.renderedBlocks.getCache(cacheKey, route.block, function(err, layout) {</td></tr><tr class="miss"><td class="line">226</td><td class="hits">0</td><td class="source">                      if (layout) res.layout = layout;</td></tr><tr class="miss"><td class="line">227</td><td class="hits">0</td><td class="source">                      group()(err);</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source">                    });</td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source">                  } else {</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source">                    // Execute the module route function and cache the result</td></tr><tr class="miss"><td class="line">232</td><td class="hits">0</td><td class="source">                    self.routeFn(req, res, route, group());</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source">                  }</td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source">                });</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">237</td><td class="hits"></td><td class="source">              } else {</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">239</td><td class="hits">10</td><td class="source">                self.routeFn(req, res, route, group());</td></tr><tr><td class="line">240</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">244</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">245</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">247</td><td class="hits"></td><td class="source">        },</td></tr><tr><td class="line">248</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">        function allMatched(err) {</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source">          // Once all functions have been called, log the error and pass it back up the tree.</td></tr><tr class="hit"><td class="line">252</td><td class="hits">16</td><td class="source">          if (err) {</td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">            // Enrich the error message with info on the module</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source">            // calipso.error(&quot;Error in module &quot; + this.moduleName + &quot;, of &quot; + err.message);</td></tr><tr class="miss"><td class="line">255</td><td class="hits">0</td><td class="source">            err.message = err.message + &quot; Calipso Module: &quot; + self.moduleName;</td></tr><tr><td class="line">256</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source">          // Emit routed event</td></tr><tr class="hit"><td class="line">259</td><td class="hits">16</td><td class="source">          next(err, self.moduleName);</td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source">        });</td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source">      },</td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source">      // Wrapper for router</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source">      // This deals with legacy modules pre 0.3.0 (will remove later)</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source">      routeFn: function(req, res, route, next) {</td></tr><tr><td class="line">268</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">269</td><td class="hits">10</td><td class="source">        if (typeof route.fn !== &quot;function&quot;) console.dir(route);</td></tr><tr><td class="line">270</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">271</td><td class="hits">10</td><td class="source">        var legacyRouteFn = route.fn.length === 5 ? true : false;</td></tr><tr class="hit"><td class="line">272</td><td class="hits">10</td><td class="source">        if (legacyRouteFn) {</td></tr><tr class="miss"><td class="line">273</td><td class="hits">0</td><td class="source">          route.fn(req, res, route.templateFn, route.block, next);</td></tr><tr><td class="line">274</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="hit"><td class="line">275</td><td class="hits">10</td><td class="source">          route.fn(req, res, route, next);</td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">277</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">278</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">280</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">281</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">285</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source"> * Normalize the given path string,</td></tr><tr><td class="line">287</td><td class="hits"></td><td class="source"> * returning a regular expression.</td></tr><tr><td class="line">288</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">289</td><td class="hits"></td><td class="source"> * An empty array should be passed,</td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source"> * which will contain the placeholder</td></tr><tr><td class="line">291</td><td class="hits"></td><td class="source"> * key names. For example &quot;/user/:id&quot; will</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> * then contain [&quot;id&quot;].</td></tr><tr><td class="line">293</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">294</td><td class="hits"></td><td class="source"> * BORROWED FROM Connect</td></tr><tr><td class="line">295</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">296</td><td class="hits"></td><td class="source"> * @param  {String} path</td></tr><tr><td class="line">297</td><td class="hits"></td><td class="source"> * @param  {Array} keys</td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source"> * @return {RegExp}</td></tr><tr><td class="line">299</td><td class="hits"></td><td class="source"> * @api private</td></tr><tr><td class="line">300</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">302</td><td class="hits">1</td><td class="source">function normalizePath(path, keys) {</td></tr><tr class="hit"><td class="line">303</td><td class="hits">8</td><td class="source">  path = path.concat('/?').replace(/\/\(/g, '(?:/').replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional) {</td></tr><tr class="miss"><td class="line">304</td><td class="hits">0</td><td class="source">    keys.push(key);</td></tr><tr class="miss"><td class="line">305</td><td class="hits">0</td><td class="source">    slash = slash || '';</td></tr><tr class="miss"><td class="line">306</td><td class="hits">0</td><td class="source">    return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || '([^/]+?)') + ')' + (optional || '');</td></tr><tr><td class="line">307</td><td class="hits"></td><td class="source">  }).replace(/([\/.])/g, '\\$1').replace(/\*/g, '(.+)');</td></tr><tr><td class="line">308</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">309</td><td class="hits">8</td><td class="source">  return new RegExp('^' + path + '$', 'i');</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">311</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">312</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">313</td><td class="hits"></td><td class="source"> * Exports</td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">315</td><td class="hits">1</td><td class="source">module.exports = Router;</td></tr></tbody></table></div><div class="file"><h2 id="core/Storage.js">core/Storage.js</h2><div id="stats" class="high"><div class="percentage">100%</div><div class="sloc">35</div><div class="hits">35</div><div class="misses">0</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso MongoDB Storage Library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * This library provides a few simple functions that can be used to help manage MongoDB and Mongoose.</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">9</td><td class="hits">1</td><td class="source">var rootpath = process.cwd(),</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">  events = require('events'),</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">  mongoStore = require(path.join(rootpath, 'support/connect-mongodb')),</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">  mongoose = require('mongoose'),</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso'));</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">16</td><td class="hits">1</td><td class="source">function Storage() {</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">  // Store running map reduce functions</td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">  this.mr = {};</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> * Check that the mongodb instance specified in the configuration is valid.</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">24</td><td class="hits">1</td><td class="source">Storage.prototype.mongoConnect = function(dbUri, checkInstalling, next) {</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source">  // Test the mongodb configuration</td></tr><tr class="hit"><td class="line">27</td><td class="hits">8</td><td class="source">  var isInstalled = calipso.config.get('installed');</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">  // If first option is callback, ste dbUri to config value</td></tr><tr class="hit"><td class="line">30</td><td class="hits">8</td><td class="source">  if (typeof dbUri === &quot;function&quot;) {</td></tr><tr class="hit"><td class="line">31</td><td class="hits">4</td><td class="source">    next = dbUri;</td></tr><tr class="hit"><td class="line">32</td><td class="hits">4</td><td class="source">    dbUri = calipso.config.get('database:uri');</td></tr><tr class="hit"><td class="line">33</td><td class="hits">4</td><td class="source">    checkInstalling = false;</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">  // Check we are installing ...</td></tr><tr class="hit"><td class="line">37</td><td class="hits">8</td><td class="source">  if (checkInstalling) {</td></tr><tr class="hit"><td class="line">38</td><td class="hits">2</td><td class="source">    var db = mongoose.createConnection(dbUri, function(err) {</td></tr><tr class="hit"><td class="line">39</td><td class="hits">2</td><td class="source">      next(err, false);</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">41</td><td class="hits">2</td><td class="source">    return;</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">44</td><td class="hits">6</td><td class="source">  if (isInstalled) {</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">    // Always disconnect first just in case any left overs from installation</td></tr><tr class="hit"><td class="line">47</td><td class="hits">5</td><td class="source">    mongoose.disconnect(function() {</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">      // TODO - what the hell is going on with mongoose?</td></tr><tr class="hit"><td class="line">50</td><td class="hits">5</td><td class="source">      calipso.db = mongoose.createConnection(dbUri, function(err) {</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">52</td><td class="hits">5</td><td class="source">        if (err) {</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">54</td><td class="hits">1</td><td class="source">          calipso.error(&quot;Unable to connect to the specified database &quot;.red + dbUri + &quot;, the problem was: &quot;.red + err.message);</td></tr><tr class="hit"><td class="line">55</td><td class="hits">1</td><td class="source">          mongoose.disconnect(function() {</td></tr><tr class="hit"><td class="line">56</td><td class="hits">1</td><td class="source">            return next(err, false);</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source">        } else {</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">61</td><td class="hits">4</td><td class="source">          calipso.silly(&quot;Database connection to &quot; + dbUri + &quot; was successful.&quot;);</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">          // Replace the inmemory session with mongodb backed one</td></tr><tr class="hit"><td class="line">64</td><td class="hits">4</td><td class="source">          var foundMiddleware = false, mw;</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">66</td><td class="hits">4</td><td class="source">          calipso.app.stack.forEach(function(middleware, key) {</td></tr><tr class="hit"><td class="line">67</td><td class="hits">9</td><td class="source">            if (middleware.handle.tag === 'session') {</td></tr><tr class="hit"><td class="line">68</td><td class="hits">3</td><td class="source">              foundMiddleware = true;</td></tr><tr class="hit"><td class="line">69</td><td class="hits">3</td><td class="source">              mw = calipso.lib.express.session({</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">                secret: calipso.config.get('session:secret'),</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">                store: mongoStore({</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">                  url: calipso.config.get('database:uri')</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">                })</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source">              });</td></tr><tr class="hit"><td class="line">75</td><td class="hits">3</td><td class="source">              mw.tag = 'session';</td></tr><tr class="hit"><td class="line">76</td><td class="hits">3</td><td class="source">              calipso.app.stack[key].handle = mw;</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">80</td><td class="hits">4</td><td class="source">          if (!foundMiddleware) {</td></tr><tr class="hit"><td class="line">81</td><td class="hits">1</td><td class="source">            return next(new Error(&quot;Unable to load the MongoDB backed session, please check your session and db configuration&quot;), false);</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">84</td><td class="hits">3</td><td class="source">          return next(null, true);</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">92</td><td class="hits">1</td><td class="source">    calipso.silly(&quot;Database connection not attempted to &quot; + dbUri + &quot; as in installation mode.&quot;);</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">    // Create a dummy connection to enable models to be defined</td></tr><tr class="hit"><td class="line">95</td><td class="hits">1</td><td class="source">    calipso.db = mongoose.createConnection('');</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">97</td><td class="hits">1</td><td class="source">    next(null, false);</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">103</td><td class="hits">1</td><td class="source">module.exports = new Storage();</td></tr></tbody></table></div><div class="file"><h2 id="core/Table.js">core/Table.js</h2><div id="stats" class="medium"><div class="percentage">70%</div><div class="sloc">65</div><div class="hits">46</div><div class="misses">19</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * Calipso Table Rendering Library</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> * Loaded into calipso as a plugin, used to simplify the rendering of tabular data.</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * Including things such as rendering table sorting elements etc.</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * TODO: validation, redisplay of submitted values</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">14</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">  qs = require('qs'),</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source">  pager = require(path.join(rootpath, 'utils/pager')),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">  merge = require('connect').utils.merge;</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">// Global variable (in this context) for translation function</td></tr><tr class="hit"><td class="line">22</td><td class="hits">1</td><td class="source">var t;</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> * The default calipso table object, with default configuration values.</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> * Constructor</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">29</td><td class="hits">1</td><td class="source">function CalipsoTable() {</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">  //TODO Allow over-ride</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> * Export an instance of our table object</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">37</td><td class="hits">1</td><td class="source">module.exports = new CalipsoTable();</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source"> * Table Renderer, controls the overall creation of the tablle based on a form json object passed</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> * in as the first parameter.  The structure of this object is as follows:</td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source"> *     table</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source"> *        id : Unique ID that will become the form ID.</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> *        title : Title to show at the top of the form.</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> *        cls : css class</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> *      columns [*] : Form fields array - can be in form or section.</td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source"> *        label : Label for form field.</td></tr><tr><td class="line">50</td><td class="hits"></td><td class="source"> *        name : Name of form element to be passed back with the value.</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source"> *        type : Type of element, based on the form functions defined below.</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> *        sortable : true / false</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source"> *        fn : Function to apply to the row</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> *      data [*] : Array of buttons to be rendered at the bottom of the form.</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source"> *      view : COntrols display of this form</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source"> *        pager : show pager</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source"> *        from  : from page</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source"> *        to    : to page</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> *        url   : base url for links</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> *        sort  : {} of sort field name:dir (asc|desc)</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source"> *  This is synchronous so that it can be called from views.</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source"> * @param item : the json object representing the table</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> * @param req : The request object</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">67</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.render = function(req, item) {</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source">  // Store local reference to the request for use during translation</td></tr><tr class="hit"><td class="line">70</td><td class="hits">1</td><td class="source">  t = req.t;</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">72</td><td class="hits">1</td><td class="source">  return (</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source">  this.start_table(item) + this.render_headers(item) + this.render_data(item, req) + this.end_table(item) + this.render_pager(item, item.view.url));</td></tr><tr><td class="line">74</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">78</td><td class="hits"></td><td class="source"> * Render the initial table tag</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source"> * @param form</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">82</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">83</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.start_table = function(table) {</td></tr><tr class="hit"><td class="line">84</td><td class="hits">1</td><td class="source">  return ('&lt;table id=&quot;' + table.id + '&quot;' + (table.cls ? ' class=&quot;' + table.cls + '&quot;' : &quot;&quot;) + '&gt;');</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source"> * Close the table</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source"> * @param table</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">92</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.end_table = function(table) {</td></tr><tr class="hit"><td class="line">93</td><td class="hits">1</td><td class="source">  return '&lt;/table&gt;';</td></tr><tr><td class="line">94</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">97</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> * Render headers</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> * @param table</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">102</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.render_headers = function(table) {</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source">  // If there are no columns, return</td></tr><tr class="hit"><td class="line">105</td><td class="hits">1</td><td class="source">  if (table.columns.length === 0) throw new Error(&quot;You must define columns to render a table.&quot;);</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">107</td><td class="hits"></td><td class="source">  // Test</td></tr><tr class="hit"><td class="line">108</td><td class="hits">1</td><td class="source">  var output = &quot;&lt;thead&gt;&lt;tr&gt;&quot;;</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">110</td><td class="hits"></td><td class="source">  // Iterate</td></tr><tr class="hit"><td class="line">111</td><td class="hits">1</td><td class="source">  table.columns.forEach(function(column, key) {</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">113</td><td class="hits"></td><td class="source">    // set the class</td></tr><tr><td class="line">114</td><td class="hits"></td><td class="source">    // Check to see if we are sorting by this column</td></tr><tr class="hit"><td class="line">115</td><td class="hits">3</td><td class="source">    var cls = getHeaderClass(table, column);</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">117</td><td class="hits">3</td><td class="source">    output += &quot;&lt;th&quot; + (' class=&quot;' + cls + '&quot;') + (column.sort ? ' name=&quot;' + column.sort + '&quot;' : (column.name ? ' name=&quot;' + column.name + '&quot;' : &quot;&quot;)) + &quot;&gt;&quot;;</td></tr><tr class="hit"><td class="line">118</td><td class="hits">3</td><td class="source">    output += column.label;</td></tr><tr class="hit"><td class="line">119</td><td class="hits">3</td><td class="source">    output += &quot;&lt;/th&gt;&quot;;</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">122</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">123</td><td class="hits">1</td><td class="source">  output += &quot;&lt;/tr&gt;&lt;/thead&gt;&quot;;</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">125</td><td class="hits">1</td><td class="source">  return output;</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">129</td><td class="hits"></td><td class="source">/** </td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source"> * Helper function to determine column header sort class</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">132</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">133</td><td class="hits">1</td><td class="source">function getHeaderClass(table, column) {</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">  // Default class</td></tr><tr class="hit"><td class="line">136</td><td class="hits">3</td><td class="source">  var cls = column.cls || '';</td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source">  // Sortable</td></tr><tr class="hit"><td class="line">138</td><td class="hits">3</td><td class="source">  cls += column.sortable === false ? '' : 'sortable';</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">140</td><td class="hits">3</td><td class="source">  if (table.view &amp;&amp; table.view.sort &amp;&amp; (table.view.sort[column.name] || table.view.sort[column.sort])) {</td></tr><tr class="miss"><td class="line">141</td><td class="hits">0</td><td class="source">    cls += ' sorted-' + (table.view.sort[column.sort] || table.view.sort[column.name]);</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">    // Leave as is</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">145</td><td class="hits">3</td><td class="source">  return cls;</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source"> * Convert a sortBy parameter into mongo sort queries</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">152</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.sortQuery = function(qry, sortBy) {</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">154</td><td class="hits">0</td><td class="source">  if (typeof sortBy === 'string') sortBy = [sortBy];</td></tr><tr class="miss"><td class="line">155</td><td class="hits">0</td><td class="source">  if (!sortBy || sortBy.length === 0) return qry;</td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">157</td><td class="hits">0</td><td class="source">  sortBy.forEach(function(sort) {</td></tr><tr class="miss"><td class="line">158</td><td class="hits">0</td><td class="source">    var sortArr = sort.split(&quot;,&quot;);</td></tr><tr class="miss"><td class="line">159</td><td class="hits">0</td><td class="source">    if (sortArr.length === 2) {</td></tr><tr class="miss"><td class="line">160</td><td class="hits">0</td><td class="source">      var dir = sortArr[1] === 'asc' ? 1 : (sortArr[1] === 'desc' ? -1 : 0);</td></tr><tr class="miss"><td class="line">161</td><td class="hits">0</td><td class="source">      qry = qry.sort(sortArr[0], dir);</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">165</td><td class="hits">0</td><td class="source">  return qry;</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source"> * Convert a sort by form param into a view sort object</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">172</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.parseSort = function(sortBy) {</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">174</td><td class="hits">0</td><td class="source">  var options = {};</td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">176</td><td class="hits">0</td><td class="source">  if (typeof sortBy === 'string') sortBy = [sortBy];</td></tr><tr class="miss"><td class="line">177</td><td class="hits">0</td><td class="source">  if (!sortBy || sortBy.length === 0) return options;</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">179</td><td class="hits">0</td><td class="source">  sortBy.forEach(function(sort) {</td></tr><tr class="miss"><td class="line">180</td><td class="hits">0</td><td class="source">    var sortArr = sort.split(&quot;,&quot;);</td></tr><tr class="miss"><td class="line">181</td><td class="hits">0</td><td class="source">    if (sortArr.length === 2) {</td></tr><tr class="miss"><td class="line">182</td><td class="hits">0</td><td class="source">      options[sortArr[0]] = sortArr[1];</td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">186</td><td class="hits">0</td><td class="source">  return options;</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> * Render headers</td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source"> * @param table</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">195</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.render_data = function(table, req) {</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source">  // If there are no columns, return</td></tr><tr class="hit"><td class="line">198</td><td class="hits">1</td><td class="source">  if (table.columns.length === 0) throw new Error(&quot;You must define columns to render a table.&quot;);</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source">  // Test</td></tr><tr class="hit"><td class="line">201</td><td class="hits">1</td><td class="source">  var output = &quot;&lt;tbody&gt;&quot;;</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">  // Iterate</td></tr><tr class="hit"><td class="line">204</td><td class="hits">1</td><td class="source">  table.data.forEach(function(row) {</td></tr><tr class="hit"><td class="line">205</td><td class="hits">2</td><td class="source">    output += &quot;&lt;tr&gt;&quot;;</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source">    // Iterate over the columns</td></tr><tr class="hit"><td class="line">207</td><td class="hits">2</td><td class="source">    table.columns.forEach(function(column) {</td></tr><tr class="hit"><td class="line">208</td><td class="hits">6</td><td class="source">      output += &quot;&lt;td&gt;&quot;;</td></tr><tr class="hit"><td class="line">209</td><td class="hits">6</td><td class="source">      if (column.name in row) {</td></tr><tr class="hit"><td class="line">210</td><td class="hits">6</td><td class="source">        if (typeof column.fn === &quot;function&quot;) {</td></tr><tr class="miss"><td class="line">211</td><td class="hits">0</td><td class="source">          output += column.fn(req, row);</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="hit"><td class="line">213</td><td class="hits">6</td><td class="source">          output += row[column.name];</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="miss"><td class="line">216</td><td class="hits">0</td><td class="source">        output += &quot;Invalid: &quot; + column.name;</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source">      }</td></tr><tr class="hit"><td class="line">218</td><td class="hits">6</td><td class="source">      output += &quot;&lt;/td&gt;&quot;;</td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">    });</td></tr><tr class="hit"><td class="line">220</td><td class="hits">2</td><td class="source">    output += &quot;&lt;/tr&gt;&quot;;</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">222</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">223</td><td class="hits">1</td><td class="source">  return output + &quot;&lt;/tbody&gt;&quot;;</td></tr><tr><td class="line">224</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">225</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">226</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">227</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source"> * Render headers</td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source"> * @param table</td></tr><tr><td class="line">230</td><td class="hits"></td><td class="source"> * @returns {String}</td></tr><tr><td class="line">231</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">232</td><td class="hits">1</td><td class="source">CalipsoTable.prototype.render_pager = function(table, url) {</td></tr><tr><td class="line">233</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source">  // Test</td></tr><tr class="hit"><td class="line">235</td><td class="hits">1</td><td class="source">  var output = &quot;&quot;;</td></tr><tr><td class="line">236</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">237</td><td class="hits">1</td><td class="source">  if (table.view &amp;&amp; table.view.pager) {</td></tr><tr class="hit"><td class="line">238</td><td class="hits">1</td><td class="source">    output += pager.render(table.view.from, table.view.limit, table.view.total, url);</td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">240</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">241</td><td class="hits">1</td><td class="source">  return output;</td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">243</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="core/Themes.js">core/Themes.js</h2><div id="stats" class="medium"><div class="percentage">66%</div><div class="sloc">233</div><div class="hits">154</div><div class="misses">79</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/*!</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * Calipso theme library</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> * Copyright(c) 2011 Clifton Cunningham &lt;clifton.cunningham@gmail.com&gt;</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * MIT Licensed</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> * This library provides all of the template loading, caching and rendering functions used by Calipso.</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> * The idea is that modules only ever provide generic, unstyled html (or json), where all layout and styling is completely</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source"> * controlled by the theme.  Themes should be able to be reloaded on configuration change, and the theme engine</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source"> * will watch for changes to templates (based on config) to speed up development.</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source"> * Additionally, configuration of layouts has been extracted out into a theme configuration file, enabling control of</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> * the 'wiring' to an extent.</td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * Decision was made to not use the default express view renderers as it didn't give enough control over caching templates,</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> * Interacting with the view libraries directly,</td></tr><tr><td class="line">18</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> * Borrowed liberally from Connect / ExpressJS itself for this, thanks for the great work!</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">24</td><td class="hits"></td><td class="source"> * Includes</td></tr><tr><td class="line">25</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">27</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">28</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">  fs = require('fs'),</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">  utils = require('connect').utils,</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">  merge = utils.merge;</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source"> * The theme object itself, instantiated within calipso</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">37</td><td class="hits">1</td><td class="source">module.exports.Theme = function(theme, next) {</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">  // Defaults</td></tr><tr class="hit"><td class="line">40</td><td class="hits">2</td><td class="source">  var themeName = theme.name;</td></tr><tr class="hit"><td class="line">41</td><td class="hits">2</td><td class="source">  var themePath = theme.path;</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">43</td><td class="hits"></td><td class="source">  /**</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">   * Load a theme</td></tr><tr><td class="line">45</td><td class="hits"></td><td class="source">   */</td></tr><tr class="hit"><td class="line">46</td><td class="hits">2</td><td class="source">  loadTheme(themeName, themePath, function(err, themeConfig) {</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">48</td><td class="hits">2</td><td class="source">    if (err) {</td></tr><tr class="miss"><td class="line">49</td><td class="hits">0</td><td class="source">      next(err);</td></tr><tr class="miss"><td class="line">50</td><td class="hits">0</td><td class="source">      return;</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">52</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">53</td><td class="hits">2</td><td class="source">    cacheTheme(themeConfig, themePath, function(err, themeCache) {</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">55</td><td class="hits">2</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">56</td><td class="hits">0</td><td class="source">        next(err);</td></tr><tr class="miss"><td class="line">57</td><td class="hits">0</td><td class="source">        return;</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">      // Load the theme configuration file.</td></tr><tr class="hit"><td class="line">61</td><td class="hits">2</td><td class="source">      var theme = {</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">        theme: themeName,</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">        cache: themeCache,</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">        config: themeConfig,</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source">        compileTemplate: function(data, templatePath, templateExtension) {</td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">          // expose private function for module to use</td></tr><tr class="hit"><td class="line">67</td><td class="hits">2</td><td class="source">          return compileTemplate(data, templatePath, templateExtension);</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">        },</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">        // Render a module</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">        // Changed in 0.1.1 to be asynch</td></tr><tr><td class="line">72</td><td class="hits"></td><td class="source">        renderItem: function(req, res, template, block, options, next) {</td></tr><tr><td class="line">73</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">74</td><td class="hits">1</td><td class="source">          var output = &quot;&quot;;</td></tr><tr><td class="line">75</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">76</td><td class="hits">1</td><td class="source">          if (template) {</td></tr><tr><td class="line">77</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">78</td><td class="hits">1</td><td class="source">            var themeOptions = createOptions(req, res, options);</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">80</td><td class="hits">1</td><td class="source">            if (typeof template === 'function') {</td></tr><tr class="hit"><td class="line">81</td><td class="hits">1</td><td class="source">              try {</td></tr><tr class="hit"><td class="line">82</td><td class="hits">1</td><td class="source">                output = template.call({}, themeOptions);</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source">              } catch (ex) {</td></tr><tr class="miss"><td class="line">84</td><td class="hits">0</td><td class="source">                output = &quot;Block: &quot; + block + &quot; failed to render because &quot; + ex.message + ex.stack;</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source">              }</td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">87</td><td class="hits"></td><td class="source">            } else {</td></tr><tr><td class="line">88</td><td class="hits"></td><td class="source">              // Assume template is processed HTML</td></tr><tr class="miss"><td class="line">89</td><td class="hits">0</td><td class="source">              output = template;</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">92</td><td class="hits">1</td><td class="source">            if (block) {</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">              // Store the block and layout</td></tr><tr class="hit"><td class="line">94</td><td class="hits">1</td><td class="source">              res.renderedBlocks.set(block, output, res.layout, res.params, next);</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source">            } else {</td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">              // Just return back to the calling function</td></tr><tr class="miss"><td class="line">97</td><td class="hits">0</td><td class="source">              next(null, output);</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source">        },</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source">        render: function(req, res, next) {</td></tr><tr><td class="line">104</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">105</td><td class="hits">3</td><td class="source">          var cache = this.cache, theme = this, layout = res.layout ? res.layout : &quot;default&quot;, content, themeOptions, err;</td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">107</td><td class="hits">3</td><td class="source">          calipso.silly(&quot;Using layout &quot; + layout);</td></tr><tr><td class="line">108</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">109</td><td class="hits">3</td><td class="source">          if (!theme.config.layouts[layout]) {</td></tr><tr class="miss"><td class="line">110</td><td class="hits">0</td><td class="source">            layout = &quot;default&quot;;</td></tr><tr class="miss"><td class="line">111</td><td class="hits">0</td><td class="source">            if (!theme.config.layouts[layout]) {</td></tr><tr class="miss"><td class="line">112</td><td class="hits">0</td><td class="source">              calipso.error(&quot;Default layout is not defined within the current theme, exiting.&quot;);</td></tr><tr class="miss"><td class="line">113</td><td class="hits">0</td><td class="source">              res.send(&quot;&quot;);</td></tr><tr class="miss"><td class="line">114</td><td class="hits">0</td><td class="source">              return;</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">118</td><td class="hits">3</td><td class="source">          processTheme(req, res, layout, theme, function(err) {</td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source">            // If something went wrong ...</td></tr><tr class="hit"><td class="line">121</td><td class="hits">3</td><td class="source">            if (err) {</td></tr><tr class="miss"><td class="line">122</td><td class="hits">0</td><td class="source">              next(err, null);</td></tr><tr class="miss"><td class="line">123</td><td class="hits">0</td><td class="source">              return;</td></tr><tr><td class="line">124</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">125</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source">            // Now, process the layout template itself</td></tr><tr class="hit"><td class="line">127</td><td class="hits">3</td><td class="source">            themeOptions = createOptions(req, res, res.bufferedOutput);</td></tr><tr><td class="line">128</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">129</td><td class="hits">3</td><td class="source">            try {</td></tr><tr class="hit"><td class="line">130</td><td class="hits">3</td><td class="source">              content = theme.cache[layout].template.call({}, themeOptions);</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source">            } catch (ex) {</td></tr><tr class="miss"><td class="line">132</td><td class="hits">0</td><td class="source">              err = ex;</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">            }</td></tr><tr><td class="line">134</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">135</td><td class="hits">3</td><td class="source">            return next(err, content);</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">137</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">        },</td></tr><tr><td class="line">141</td><td class="hits"></td><td class="source">        getLayoutsArray: function() {</td></tr><tr><td class="line">142</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">143</td><td class="hits">0</td><td class="source">          var theme = this;</td></tr><tr class="miss"><td class="line">144</td><td class="hits">0</td><td class="source">          var layouts = [];</td></tr><tr class="miss"><td class="line">145</td><td class="hits">0</td><td class="source">          for (var layout in theme.config.layouts) {</td></tr><tr class="miss"><td class="line">146</td><td class="hits">0</td><td class="source">            layouts.push(layout);</td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source">          }</td></tr><tr class="miss"><td class="line">148</td><td class="hits">0</td><td class="source">          return layouts;</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">154</td><td class="hits">2</td><td class="source">      next(null, theme);</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source"> *Process a theme section</td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">167</td><td class="hits">1</td><td class="source">function processSection(req, res, section, sectionPath, layoutConfig, theme, next) {</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">169</td><td class="hits">18</td><td class="source">  var themeOptions, sectionCache = theme.cache[sectionPath];</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source">  // Check the theme cache</td></tr><tr class="hit"><td class="line">172</td><td class="hits">18</td><td class="source">  if (!sectionCache) {</td></tr><tr class="miss"><td class="line">173</td><td class="hits">0</td><td class="source">    calipso.error(&quot;Unable to find template for &quot; + sectionPath);</td></tr><tr class="miss"><td class="line">174</td><td class="hits">0</td><td class="source">    next();</td></tr><tr class="miss"><td class="line">175</td><td class="hits">0</td><td class="source">    return;</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">178</td><td class="hits">18</td><td class="source">  var blockData = &quot;&quot;;</td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">180</td><td class="hits">18</td><td class="source">  if (!sectionCache.template) {</td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">    // Use the default</td></tr><tr class="miss"><td class="line">182</td><td class="hits">0</td><td class="source">    sectionPath = &quot;default.&quot; + section;</td></tr><tr class="miss"><td class="line">183</td><td class="hits">0</td><td class="source">    sectionCache = theme.cache[sectionPath];</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source">  // should there be more than just these two error codes?</td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source">  // if more than just these two, then this would have to happen later on:</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">  // templates.push({name:&quot;500&quot;, templatePath:&quot;templates/500.html&quot;});</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source">  // Override with a 404 (not found) page</td></tr><tr class="hit"><td class="line">190</td><td class="hits">18</td><td class="source">  if (section === &quot;body&quot; &amp;&amp; res.statusCode === 404) {</td></tr><tr class="hit"><td class="line">191</td><td class="hits">1</td><td class="source">    if (!theme.cache.hasOwnProperty(&quot;404&quot;)) {</td></tr><tr class="miss"><td class="line">192</td><td class="hits">0</td><td class="source">      localNext(new Error(&quot;You must define a 404 template in the error folder e.g. error/404.html&quot;));</td></tr><tr class="miss"><td class="line">193</td><td class="hits">0</td><td class="source">      return;</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">195</td><td class="hits">1</td><td class="source">    sectionCache = theme.cache[&quot;404&quot;];</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">  // Override with a 500 (error) page</td></tr><tr class="hit"><td class="line">199</td><td class="hits">18</td><td class="source">  if (section === &quot;body&quot; &amp;&amp; res.statusCode === 500) {</td></tr><tr class="miss"><td class="line">200</td><td class="hits">0</td><td class="source">    if (!theme.cache.hasOwnProperty(&quot;500&quot;)) {</td></tr><tr class="miss"><td class="line">201</td><td class="hits">0</td><td class="source">      localNext(new Error(&quot;You must define a 500 template in the error folder e.g. error/500.html&quot;));</td></tr><tr class="miss"><td class="line">202</td><td class="hits">0</td><td class="source">      return;</td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">204</td><td class="hits">0</td><td class="source">    sectionCache = theme.cache[&quot;500&quot;];</td></tr><tr class="miss"><td class="line">205</td><td class="hits">0</td><td class="source">    blockData = res.errorMessage ? res.errorMessage : &quot;&quot;;</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source">  // Retrieve any backing function</td></tr><tr class="hit"><td class="line">209</td><td class="hits">18</td><td class="source">  var sectionCacheFn = sectionCache.fn;</td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">  // Clear any buffered output for this section</td></tr><tr class="hit"><td class="line">212</td><td class="hits">18</td><td class="source">  res.bufferedOutput[section] = &quot;&quot;;</td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source">  // Get the basic theme options</td></tr><tr class="hit"><td class="line">215</td><td class="hits">18</td><td class="source">  themeOptions = createOptions(req, res, {</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source">    blockData: blockData</td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">219</td><td class="hits"></td><td class="source">  // Add any custom functions</td></tr><tr class="hit"><td class="line">220</td><td class="hits">18</td><td class="source">  if (typeof sectionCacheFn === &quot;function&quot;) {</td></tr><tr><td class="line">221</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">222</td><td class="hits">8</td><td class="source">    sectionCacheFn(req, themeOptions, function(err, fnOptions) {</td></tr><tr><td class="line">223</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">224</td><td class="hits">8</td><td class="source">      if (err) {</td></tr><tr class="miss"><td class="line">225</td><td class="hits">0</td><td class="source">        err.xMessage = &quot;Issue executing the theme function for section &quot; + section + &quot;, check &quot; + sectionPath.replace(&quot;.&quot;, &quot;/&quot;) + &quot;.js&quot;;</td></tr><tr class="miss"><td class="line">226</td><td class="hits">0</td><td class="source">        localNext(err);</td></tr><tr class="miss"><td class="line">227</td><td class="hits">0</td><td class="source">        return;</td></tr><tr><td class="line">228</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">229</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">230</td><td class="hits">8</td><td class="source">      themeOptions = merge(themeOptions, fnOptions);</td></tr><tr class="hit"><td class="line">231</td><td class="hits">8</td><td class="source">      try {</td></tr><tr class="hit"><td class="line">232</td><td class="hits">8</td><td class="source">        res.bufferedOutput[section] += sectionCache.template.call({}, themeOptions);</td></tr><tr class="hit"><td class="line">233</td><td class="hits">8</td><td class="source">        localNext();</td></tr><tr><td class="line">234</td><td class="hits"></td><td class="source">      } catch (ex) {</td></tr><tr><td class="line">235</td><td class="hits"></td><td class="source">        // Augment the exception</td></tr><tr class="miss"><td class="line">236</td><td class="hits">0</td><td class="source">        ex.xMessage = &quot;Issue processing theme section &quot; + section + &quot;, path: &quot; + sectionPath;</td></tr><tr class="miss"><td class="line">237</td><td class="hits">0</td><td class="source">        localNext(ex);</td></tr><tr><td class="line">238</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">239</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">240</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">241</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">242</td><td class="hits"></td><td class="source">  } else {</td></tr><tr class="hit"><td class="line">243</td><td class="hits">10</td><td class="source">    try {</td></tr><tr class="hit"><td class="line">244</td><td class="hits">10</td><td class="source">      res.bufferedOutput[section] += sectionCache.template.call({}, themeOptions);</td></tr><tr class="hit"><td class="line">245</td><td class="hits">10</td><td class="source">      localNext();</td></tr><tr><td class="line">246</td><td class="hits"></td><td class="source">    } catch (ex) {</td></tr><tr class="miss"><td class="line">247</td><td class="hits">0</td><td class="source">      ex.xMessage = &quot;Issue processing theme section: &quot; + section + &quot;, theme: &quot; + sectionPath;</td></tr><tr class="miss"><td class="line">248</td><td class="hits">0</td><td class="source">      localNext(ex);</td></tr><tr><td class="line">249</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">250</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">251</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">252</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">253</td><td class="hits"></td><td class="source">  // Local next function to enable proxying of callback</td></tr><tr><td class="line">254</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">255</td><td class="hits">18</td><td class="source">  function localNext(err) {</td></tr><tr class="hit"><td class="line">256</td><td class="hits">18</td><td class="source">    next(err);</td></tr><tr><td class="line">257</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">258</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">259</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">260</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">261</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">262</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">263</td><td class="hits"></td><td class="source"> * Copy the current block data over to options to render</td></tr><tr><td class="line">264</td><td class="hits"></td><td class="source"> * @param res</td></tr><tr><td class="line">265</td><td class="hits"></td><td class="source"> * @param config</td></tr><tr><td class="line">266</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">267</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">268</td><td class="hits">1</td><td class="source">function processTheme(req, res, layout, theme, next) {</td></tr><tr><td class="line">269</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">270</td><td class="hits">3</td><td class="source">  var layoutConfig, copyConfig, copySection, sectionExists, disable, sections = [],</td></tr><tr><td class="line">271</td><td class="hits"></td><td class="source">    section;</td></tr><tr><td class="line">272</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">273</td><td class="hits">3</td><td class="source">  delete res.bufferedOutput;</td></tr><tr class="hit"><td class="line">274</td><td class="hits">3</td><td class="source">  res.bufferedOutput = {};</td></tr><tr><td class="line">275</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">276</td><td class="hits"></td><td class="source">  // Scan through each layout</td></tr><tr class="hit"><td class="line">277</td><td class="hits">3</td><td class="source">  try {</td></tr><tr class="hit"><td class="line">278</td><td class="hits">3</td><td class="source">    layoutConfig = theme.config.layouts[layout].layout;</td></tr><tr><td class="line">279</td><td class="hits"></td><td class="source">  } catch (ex) {</td></tr><tr class="miss"><td class="line">280</td><td class="hits">0</td><td class="source">    next(ex.message);</td></tr><tr class="miss"><td class="line">281</td><td class="hits">0</td><td class="source">    return;</td></tr><tr><td class="line">282</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">283</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">284</td><td class="hits"></td><td class="source">  // Check to see if this layout copies default</td></tr><tr class="hit"><td class="line">285</td><td class="hits">3</td><td class="source">  if (layoutConfig.copyFrom &amp;&amp; layout != &quot;default&quot;) {</td></tr><tr><td class="line">286</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">287</td><td class="hits">1</td><td class="source">    copyConfig = theme.config.layouts[layoutConfig.copyFrom].layout;</td></tr><tr class="hit"><td class="line">288</td><td class="hits">1</td><td class="source">    layoutConfig.sections = layoutConfig.sections || {};</td></tr><tr><td class="line">289</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">290</td><td class="hits"></td><td class="source">    // Copy over any missing sections from default</td></tr><tr class="hit"><td class="line">291</td><td class="hits">1</td><td class="source">    for (copySection in copyConfig.sections) {</td></tr><tr><td class="line">292</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">293</td><td class="hits">6</td><td class="source">      sectionExists = layoutConfig.sections &amp;&amp; layoutConfig.sections[copySection];</td></tr><tr class="hit"><td class="line">294</td><td class="hits">6</td><td class="source">      disable = layoutConfig.sections &amp;&amp; layoutConfig.sections[copySection] &amp;&amp; layoutConfig.sections[copySection].disable;</td></tr><tr class="hit"><td class="line">295</td><td class="hits">6</td><td class="source">      if (!sectionExists &amp;&amp; !disable) {</td></tr><tr class="hit"><td class="line">296</td><td class="hits">6</td><td class="source">        layoutConfig.sections[copySection] = copyConfig.sections[copySection];</td></tr><tr class="hit"><td class="line">297</td><td class="hits">6</td><td class="source">        layoutConfig.sections[copySection].layout = &quot;default&quot;; // Flag override as below</td></tr><tr><td class="line">298</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">299</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">300</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">301</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">302</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">303</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">304</td><td class="hits"></td><td class="source">  // Create a section array</td></tr><tr class="hit"><td class="line">305</td><td class="hits">3</td><td class="source">  for (section in layoutConfig.sections) {</td></tr><tr class="hit"><td class="line">306</td><td class="hits">18</td><td class="source">    disable = layoutConfig.sections[section].disable;</td></tr><tr class="hit"><td class="line">307</td><td class="hits">18</td><td class="source">    if (!disable) {</td></tr><tr class="hit"><td class="line">308</td><td class="hits">18</td><td class="source">      sections.push(section);</td></tr><tr><td class="line">309</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">310</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">311</td><td class="hits">3</td><td class="source">  var totalCount = sections.length;</td></tr><tr class="hit"><td class="line">312</td><td class="hits">3</td><td class="source">  var totalDone = 0;</td></tr><tr><td class="line">313</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">314</td><td class="hits"></td><td class="source">  // Now, process all the sections</td></tr><tr><td class="line">315</td><td class="hits"></td><td class="source">  // This is done via a localNext to give us full control</td></tr><tr><td class="line">316</td><td class="hits"></td><td class="source">  //   and better ability to debug</td></tr><tr><td class="line">317</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">318</td><td class="hits">3</td><td class="source">  function localNext(err) {</td></tr><tr class="hit"><td class="line">319</td><td class="hits">18</td><td class="source">    totalDone += 1;</td></tr><tr><td class="line">320</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">321</td><td class="hits">18</td><td class="source">    if (totalDone == totalCount) {</td></tr><tr class="hit"><td class="line">322</td><td class="hits">3</td><td class="source">      next();</td></tr><tr><td class="line">323</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">324</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">325</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">326</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">327</td><td class="hits">3</td><td class="source">  for (section in layoutConfig.sections) {</td></tr><tr><td class="line">328</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">329</td><td class="hits"></td><td class="source">    // Check to see if we are overriding</td></tr><tr class="hit"><td class="line">330</td><td class="hits">18</td><td class="source">    var currentSection = section;</td></tr><tr class="hit"><td class="line">331</td><td class="hits">18</td><td class="source">    var layoutOverride = layoutConfig.sections[section].layout;</td></tr><tr class="hit"><td class="line">332</td><td class="hits">18</td><td class="source">    var sectionPath = layoutOverride ? layoutOverride + &quot;.&quot; + section : layout + &quot;.&quot; + section;</td></tr><tr class="hit"><td class="line">333</td><td class="hits">18</td><td class="source">    var cache = layoutConfig.sections[section].cache;</td></tr><tr class="hit"><td class="line">334</td><td class="hits">18</td><td class="source">    var params = layoutConfig.sections[section].varyParams;</td></tr><tr class="hit"><td class="line">335</td><td class="hits">18</td><td class="source">    var cacheEnabled = calipso.config.get('performance:cache:enabled');</td></tr><tr class="hit"><td class="line">336</td><td class="hits">18</td><td class="source">    var isAdmin = req.session.user &amp;&amp; req.session.user.isAdmin;</td></tr><tr><td class="line">337</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">338</td><td class="hits">18</td><td class="source">    disable = layoutConfig.sections[section].disable;</td></tr><tr><td class="line">339</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">340</td><td class="hits"></td><td class="source">    // Sections are cacheable</td></tr><tr class="hit"><td class="line">341</td><td class="hits">18</td><td class="source">    if (!disable) {</td></tr><tr class="hit"><td class="line">342</td><td class="hits">18</td><td class="source">      if (cache &amp;&amp; cacheEnabled &amp;&amp; !isAdmin) {</td></tr><tr class="miss"><td class="line">343</td><td class="hits">0</td><td class="source">        var keys = [layout, 'section', currentSection];</td></tr><tr class="miss"><td class="line">344</td><td class="hits">0</td><td class="source">        var cacheKey = calipso.cacheService.getCacheKey(keys, params);</td></tr><tr class="miss"><td class="line">345</td><td class="hits">0</td><td class="source">        sectionCache(req, res, cacheKey, section, sectionPath, layoutConfig, theme, localNext);</td></tr><tr><td class="line">346</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">347</td><td class="hits">18</td><td class="source">        processSection(req, res, section, sectionPath, layoutConfig, theme, localNext);</td></tr><tr><td class="line">348</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">349</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">350</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">351</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">352</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">353</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">354</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">355</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">356</td><td class="hits"></td><td class="source"> * Interact with sections via the cache</td></tr><tr><td class="line">357</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">358</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">359</td><td class="hits">1</td><td class="source">function sectionCache(req, res, cacheKey, section, templateName, layoutConfig, theme, next) {</td></tr><tr><td class="line">360</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">361</td><td class="hits">0</td><td class="source">  calipso.cacheService.check(cacheKey, function(err, isCached) {</td></tr><tr class="miss"><td class="line">362</td><td class="hits">0</td><td class="source">    if (isCached) {</td></tr><tr class="miss"><td class="line">363</td><td class="hits">0</td><td class="source">      calipso.silly(&quot;Cache hit for &quot; + cacheKey + &quot;, section &quot; + section);</td></tr><tr class="miss"><td class="line">364</td><td class="hits">0</td><td class="source">      calipso.cacheService.get(cacheKey, function(err, cache) {</td></tr><tr class="miss"><td class="line">365</td><td class="hits">0</td><td class="source">        if (!err) {</td></tr><tr class="miss"><td class="line">366</td><td class="hits">0</td><td class="source">          res.bufferedOutput[section] = cache.content;</td></tr><tr><td class="line">367</td><td class="hits"></td><td class="source">        }</td></tr><tr class="miss"><td class="line">368</td><td class="hits">0</td><td class="source">        next(err);</td></tr><tr><td class="line">369</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">370</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">371</td><td class="hits">0</td><td class="source">      calipso.silly(&quot;Cache miss for &quot; + cacheKey + &quot;, section &quot; + section);</td></tr><tr class="miss"><td class="line">372</td><td class="hits">0</td><td class="source">      processSection(req, res, section, templateName, layoutConfig, theme, function(err) {</td></tr><tr class="miss"><td class="line">373</td><td class="hits">0</td><td class="source">        if (!err) {</td></tr><tr class="miss"><td class="line">374</td><td class="hits">0</td><td class="source">          var content = res.bufferedOutput[section];</td></tr><tr class="miss"><td class="line">375</td><td class="hits">0</td><td class="source">          calipso.cacheService.set(cacheKey, {</td></tr><tr><td class="line">376</td><td class="hits"></td><td class="source">            content: content</td></tr><tr><td class="line">377</td><td class="hits"></td><td class="source">          }, null, next);</td></tr><tr><td class="line">378</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">379</td><td class="hits">0</td><td class="source">          next(err);</td></tr><tr><td class="line">380</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">381</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">382</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">383</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">384</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">385</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">386</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">387</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">388</td><td class="hits"></td><td class="source"> * Load a theme</td></tr><tr><td class="line">389</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">390</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">391</td><td class="hits">1</td><td class="source">function loadTheme(theme, themePath, next) {</td></tr><tr><td class="line">392</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">393</td><td class="hits">2</td><td class="source">  var themeFile = calipso.lib.path.join(themePath, &quot;theme.json&quot;);</td></tr><tr><td class="line">394</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">395</td><td class="hits">2</td><td class="source">  path.exists(themeFile, function(exists) {</td></tr><tr class="hit"><td class="line">396</td><td class="hits">2</td><td class="source">    if (exists) {</td></tr><tr class="hit"><td class="line">397</td><td class="hits">2</td><td class="source">      fs.readFile(themeFile, 'utf8', function(err, data) {</td></tr><tr class="hit"><td class="line">398</td><td class="hits">2</td><td class="source">        if (!err) {</td></tr><tr class="hit"><td class="line">399</td><td class="hits">2</td><td class="source">          var jsonData;</td></tr><tr class="hit"><td class="line">400</td><td class="hits">2</td><td class="source">          try {</td></tr><tr class="hit"><td class="line">401</td><td class="hits">2</td><td class="source">            jsonData = JSON.parse(data);</td></tr><tr class="hit"><td class="line">402</td><td class="hits">2</td><td class="source">            next(null, jsonData);</td></tr><tr><td class="line">403</td><td class="hits"></td><td class="source">          } catch (ex) {</td></tr><tr class="miss"><td class="line">404</td><td class="hits">0</td><td class="source">            next(new Error(&quot;Error parsing theme configuration: &quot; + ex.message + &quot; stack, &quot; + ex.stack));</td></tr><tr><td class="line">405</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">406</td><td class="hits"></td><td class="source">        } else {</td></tr><tr class="miss"><td class="line">407</td><td class="hits">0</td><td class="source">          next(err);</td></tr><tr><td class="line">408</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">409</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">410</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="miss"><td class="line">411</td><td class="hits">0</td><td class="source">      next(new Error(&quot;Can't find specified theme configuration &quot; + themeFile));</td></tr><tr><td class="line">412</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">413</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">414</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">415</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">416</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">417</td><td class="hits"></td><td class="source"> * Load all of the theme templates into the theme</td></tr><tr><td class="line">418</td><td class="hits"></td><td class="source"> * @param theme</td></tr><tr><td class="line">419</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">420</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">421</td><td class="hits">1</td><td class="source">function cacheTheme(themeConfig, themePath, next) {</td></tr><tr><td class="line">422</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">423</td><td class="hits">2</td><td class="source">  var templates = [],</td></tr><tr><td class="line">424</td><td class="hits"></td><td class="source">    templateCache = {},</td></tr><tr><td class="line">425</td><td class="hits"></td><td class="source">    layout, layoutConfig, section, template, module, templateFiles, errorCodeTemplates;</td></tr><tr><td class="line">426</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">427</td><td class="hits"></td><td class="source">  // Scan through each layout</td></tr><tr class="hit"><td class="line">428</td><td class="hits">2</td><td class="source">  if (themeConfig) {</td></tr><tr><td class="line">429</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">430</td><td class="hits">2</td><td class="source">    for (layout in themeConfig.layouts) {</td></tr><tr><td class="line">431</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">432</td><td class="hits"></td><td class="source">      // Scan through each layout</td></tr><tr class="hit"><td class="line">433</td><td class="hits">6</td><td class="source">      layoutConfig = themeConfig.layouts[layout].layout;</td></tr><tr><td class="line">434</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">435</td><td class="hits"></td><td class="source">      // Add the layout template</td></tr><tr class="hit"><td class="line">436</td><td class="hits">6</td><td class="source">      templates.push({</td></tr><tr><td class="line">437</td><td class="hits"></td><td class="source">        name: layout,</td></tr><tr><td class="line">438</td><td class="hits"></td><td class="source">        templatePath: calipso.lib.path.join(&quot;templates&quot;, layoutConfig.template)</td></tr><tr><td class="line">439</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">440</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">441</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">442</td><td class="hits"></td><td class="source">      // Add the templates</td></tr><tr class="hit"><td class="line">443</td><td class="hits">6</td><td class="source">      for (section in layoutConfig.sections) {</td></tr><tr class="hit"><td class="line">444</td><td class="hits">14</td><td class="source">        template = layoutConfig.sections[section].template;</td></tr><tr class="hit"><td class="line">445</td><td class="hits">14</td><td class="source">        if (template) {</td></tr><tr class="hit"><td class="line">446</td><td class="hits">14</td><td class="source">          templates.push({</td></tr><tr><td class="line">447</td><td class="hits"></td><td class="source">            name: layout + &quot;.&quot; + section,</td></tr><tr><td class="line">448</td><td class="hits"></td><td class="source">            templatePath: calipso.lib.path.join(&quot;templates&quot;, layout, template)</td></tr><tr><td class="line">449</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">450</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">451</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">452</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">453</td><td class="hits"></td><td class="source">      // Check to see if the theme overrides any module templates</td></tr><tr class="hit"><td class="line">454</td><td class="hits">6</td><td class="source">      if (layoutConfig.modules) {</td></tr><tr class="miss"><td class="line">455</td><td class="hits">0</td><td class="source">        for (module in layoutConfig.modules) {</td></tr><tr class="miss"><td class="line">456</td><td class="hits">0</td><td class="source">          for (template in layoutConfig.modules[module]) {</td></tr><tr class="miss"><td class="line">457</td><td class="hits">0</td><td class="source">            loadModuleOverrideTemplate(templateCache, module, template, path.join(themePath, layoutConfig.modules[module][template]));</td></tr><tr><td class="line">458</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">459</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">460</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">461</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">462</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">463</td><td class="hits"></td><td class="source">    // Push error message templates</td></tr><tr class="hit"><td class="line">464</td><td class="hits">2</td><td class="source">    templateFiles = calipso.lib.fs.readdirSync(calipso.lib.path.join(themePath, 'templates', 'error'));</td></tr><tr class="hit"><td class="line">465</td><td class="hits">2</td><td class="source">    errorCodeTemplates = calipso.lib._.select(templateFiles, function(filename) {</td></tr><tr><td class="line">466</td><td class="hits"></td><td class="source">      // Select files that start with 3 digits, indicating an error code</td></tr><tr class="hit"><td class="line">467</td><td class="hits">4</td><td class="source">      return filename.match(/^\d{3}./);</td></tr><tr><td class="line">468</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">469</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">470</td><td class="hits">2</td><td class="source">    calipso.lib._.each(errorCodeTemplates, function(filename) {</td></tr><tr class="hit"><td class="line">471</td><td class="hits">4</td><td class="source">      templates.push({</td></tr><tr><td class="line">472</td><td class="hits"></td><td class="source">        name: filename.match(/^\d{3}/)[0],</td></tr><tr><td class="line">473</td><td class="hits"></td><td class="source">        templatePath: calipso.lib.path.join(&quot;templates&quot;, &quot;error&quot;, filename)</td></tr><tr><td class="line">474</td><td class="hits"></td><td class="source">      });</td></tr><tr><td class="line">475</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">476</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">477</td><td class="hits">2</td><td class="source">    var templateIterator = function(templateName, cb) {</td></tr><tr class="hit"><td class="line">478</td><td class="hits">24</td><td class="source">        loadTemplate(templateCache, templateName, themePath, cb);</td></tr><tr><td class="line">479</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">480</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">481</td><td class="hits">2</td><td class="source">    calipso.lib.async.map(templates, templateIterator, function(err, result) {</td></tr><tr class="hit"><td class="line">482</td><td class="hits">2</td><td class="source">      if (err) {</td></tr><tr><td class="line">483</td><td class="hits"></td><td class="source">        // May not be a problem as missing templates default to default</td></tr><tr class="miss"><td class="line">484</td><td class="hits">0</td><td class="source">        calipso.error(&quot;Error loading templates, msg: &quot; + err.message + &quot;, stack: &quot; + err.stack);</td></tr><tr class="miss"><td class="line">485</td><td class="hits">0</td><td class="source">        next(err);</td></tr><tr><td class="line">486</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">487</td><td class="hits">2</td><td class="source">        next(null, templateCache);</td></tr><tr><td class="line">488</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">489</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">490</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">491</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">492</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">493</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">494</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">495</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">496</td><td class="hits"></td><td class="source"> * Load a template that overrides a module template</td></tr><tr><td class="line">497</td><td class="hits"></td><td class="source"> * fired from cacheTheme(),</td></tr><tr><td class="line">498</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">499</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">500</td><td class="hits">1</td><td class="source">function loadModuleOverrideTemplate(templateCache, module, template, path) {</td></tr><tr><td class="line">501</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">502</td><td class="hits">0</td><td class="source">  var templatePath = path,</td></tr><tr><td class="line">503</td><td class="hits"></td><td class="source">    templateExtension = templatePath.match(/([^\.]+)$/)[0],</td></tr><tr><td class="line">504</td><td class="hits"></td><td class="source">    templateFn = fs.readFileSync(templatePath, 'utf8'),</td></tr><tr><td class="line">505</td><td class="hits"></td><td class="source">    templateFnCompiled = compileTemplate(templateFn, templatePath, templateExtension);</td></tr><tr><td class="line">506</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">507</td><td class="hits"></td><td class="source">  // Initialise the objects</td></tr><tr class="miss"><td class="line">508</td><td class="hits">0</td><td class="source">  templateCache.modules = templateCache.modules || {};</td></tr><tr class="miss"><td class="line">509</td><td class="hits">0</td><td class="source">  templateCache.modules[module] = templateCache.modules[module] || {};</td></tr><tr class="miss"><td class="line">510</td><td class="hits">0</td><td class="source">  templateCache.modules[module].templates = templateCache.modules[module].templates || {};</td></tr><tr><td class="line">511</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">512</td><td class="hits"></td><td class="source">  // allow hook for listening for module events?</td></tr><tr><td class="line">513</td><td class="hits"></td><td class="source">  // Load the function</td></tr><tr class="miss"><td class="line">514</td><td class="hits">0</td><td class="source">  templateCache.modules[module].templates[template] = templateFnCompiled;</td></tr><tr><td class="line">515</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">516</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">517</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">518</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">519</td><td class="hits"></td><td class="source"> * Load a template</td></tr><tr><td class="line">520</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">521</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">522</td><td class="hits">1</td><td class="source">function loadTemplate(templateCache, template, themePath, next) {</td></tr><tr><td class="line">523</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">524</td><td class="hits"></td><td class="source">  // Reset / default</td></tr><tr class="hit"><td class="line">525</td><td class="hits">48</td><td class="source">  if (!templateCache[template.name]) templateCache[template.name] = {};</td></tr><tr><td class="line">526</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">527</td><td class="hits"></td><td class="source">  // Template paths and functions</td></tr><tr class="hit"><td class="line">528</td><td class="hits">24</td><td class="source">  var templatePath = calipso.lib.path.join(themePath, template.templatePath),</td></tr><tr><td class="line">529</td><td class="hits"></td><td class="source">    templateExtension = template.templatePath.match(/([^\.]+)$/)[0],</td></tr><tr><td class="line">530</td><td class="hits"></td><td class="source">    templateFnPath = calipso.lib.path.join(themePath, template.templatePath.replace(&quot;.&quot; + templateExtension, &quot;.js&quot;));</td></tr><tr><td class="line">531</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">532</td><td class="hits">24</td><td class="source">  path.exists(templatePath, function(exists) {</td></tr><tr><td class="line">533</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">534</td><td class="hits">24</td><td class="source">    if (exists) {</td></tr><tr><td class="line">535</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">536</td><td class="hits">24</td><td class="source">      var templateData = '';</td></tr><tr><td class="line">537</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">538</td><td class="hits">24</td><td class="source">      try {</td></tr><tr class="hit"><td class="line">539</td><td class="hits">24</td><td class="source">        templateData = fs.readFileSync(templatePath, 'utf8');</td></tr><tr><td class="line">540</td><td class="hits"></td><td class="source">      } catch (err) {</td></tr><tr class="miss"><td class="line">541</td><td class="hits">0</td><td class="source">        calipso.error('Failed to open template ' + templatePath + ' ...');</td></tr><tr><td class="line">542</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">543</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">544</td><td class="hits">24</td><td class="source">      if (calipso.config.get('performance:watchFiles')) {</td></tr><tr><td class="line">545</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">546</td><td class="hits">24</td><td class="source">        try {</td></tr><tr class="hit"><td class="line">547</td><td class="hits">24</td><td class="source">          fs.unwatchFile(templatePath);</td></tr><tr class="hit"><td class="line">548</td><td class="hits">24</td><td class="source">          fs.watchFile(templatePath, {</td></tr><tr><td class="line">549</td><td class="hits"></td><td class="source">            persistent: true,</td></tr><tr><td class="line">550</td><td class="hits"></td><td class="source">            interval: 200</td></tr><tr><td class="line">551</td><td class="hits"></td><td class="source">          }, function(curr, prev) {</td></tr><tr class="miss"><td class="line">552</td><td class="hits">0</td><td class="source">            loadTemplate(templateCache, template, themePath, function() {</td></tr><tr class="miss"><td class="line">553</td><td class="hits">0</td><td class="source">              calipso.silly(&quot;Template &quot; + templatePath + &quot; reloaded ...&quot;);</td></tr><tr><td class="line">554</td><td class="hits"></td><td class="source">            });</td></tr><tr><td class="line">555</td><td class="hits"></td><td class="source">          });</td></tr><tr><td class="line">556</td><td class="hits"></td><td class="source">        } catch (ex) {</td></tr><tr class="miss"><td class="line">557</td><td class="hits">0</td><td class="source">          calipso.error('Failed to watch template ' + templatePath + ' ...');</td></tr><tr><td class="line">558</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">559</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">560</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">561</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">562</td><td class="hits"></td><td class="source">      // Precompile the view into our cache</td></tr><tr class="hit"><td class="line">563</td><td class="hits">24</td><td class="source">      templateCache[template.name].template = compileTemplate(templateData, templatePath, templateExtension);</td></tr><tr><td class="line">564</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">565</td><td class="hits"></td><td class="source">      // See if we have a template fn</td></tr><tr class="hit"><td class="line">566</td><td class="hits">24</td><td class="source">      if (path.existsSync(templateFnPath)) {</td></tr><tr><td class="line">567</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">568</td><td class="hits">8</td><td class="source">        if (exists) {</td></tr><tr class="hit"><td class="line">569</td><td class="hits">8</td><td class="source">          try {</td></tr><tr class="hit"><td class="line">570</td><td class="hits">8</td><td class="source">            templateCache[template.name].fn = require(templateFnPath);</td></tr><tr><td class="line">571</td><td class="hits"></td><td class="source">          } catch (ex) {</td></tr><tr class="miss"><td class="line">572</td><td class="hits">0</td><td class="source">            calipso.error(ex);</td></tr><tr><td class="line">573</td><td class="hits"></td><td class="source">          }</td></tr><tr><td class="line">574</td><td class="hits"></td><td class="source">        }</td></tr><tr><td class="line">575</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">576</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">577</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">578</td><td class="hits">24</td><td class="source">      return next(null, template);</td></tr><tr><td class="line">579</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">580</td><td class="hits"></td><td class="source">    } else {</td></tr><tr><td class="line">581</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">582</td><td class="hits">0</td><td class="source">      next(new Error('Path does not exist: ' + templatePath));</td></tr><tr><td class="line">583</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">584</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">585</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">586</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">587</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">588</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">589</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">590</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">591</td><td class="hits"></td><td class="source"> * Pre-compile a template based on its extension.</td></tr><tr><td class="line">592</td><td class="hits"></td><td class="source"> * If the required view engine does not exist, exit gracefully and let</td></tr><tr><td class="line">593</td><td class="hits"></td><td class="source"> * them know that this is the case.</td></tr><tr><td class="line">594</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">595</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">596</td><td class="hits">1</td><td class="source">function compileTemplate(template, templatePath, templateExtension) {</td></tr><tr><td class="line">597</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">598</td><td class="hits">26</td><td class="source">  var compiledTemplate = function() {},</td></tr><tr><td class="line">599</td><td class="hits"></td><td class="source">    templateEngine;</td></tr><tr class="hit"><td class="line">600</td><td class="hits">26</td><td class="source">  var options = {</td></tr><tr><td class="line">601</td><td class="hits"></td><td class="source">    filename: templatePath</td></tr><tr><td class="line">602</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">603</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">604</td><td class="hits"></td><td class="source">  // If we get html, replace with ejs</td></tr><tr class="hit"><td class="line">605</td><td class="hits">52</td><td class="source">  if (templateExtension === &quot;html&quot;) templateExtension = &quot;ejs&quot;;</td></tr><tr><td class="line">606</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">607</td><td class="hits"></td><td class="source">  // Load a template engine based on the extension</td></tr><tr class="hit"><td class="line">608</td><td class="hits">26</td><td class="source">  try {</td></tr><tr class="hit"><td class="line">609</td><td class="hits">26</td><td class="source">    templateEngine = require(templateExtension);</td></tr><tr><td class="line">610</td><td class="hits"></td><td class="source">  } catch (ex) {</td></tr><tr class="miss"><td class="line">611</td><td class="hits">0</td><td class="source">    calipso.warn(&quot;No view rendering engine exists that matches: &quot; + templateExtension + &quot;, so using EJS!&quot;);</td></tr><tr class="miss"><td class="line">612</td><td class="hits">0</td><td class="source">    templateEngine = require(&quot;ejs&quot;);</td></tr><tr><td class="line">613</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">614</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">615</td><td class="hits"></td><td class="source">  // Return our compiled template</td></tr><tr class="hit"><td class="line">616</td><td class="hits">26</td><td class="source">  try {</td></tr><tr class="hit"><td class="line">617</td><td class="hits">26</td><td class="source">    compiledTemplate = templateEngine.compile(template, options);</td></tr><tr><td class="line">618</td><td class="hits"></td><td class="source">  } catch (ex) {</td></tr><tr class="miss"><td class="line">619</td><td class="hits">0</td><td class="source">    calipso.error(&quot;Error compiling template : &quot; + templatePath + &quot;, message: &quot; + ex.message);</td></tr><tr><td class="line">620</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">621</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">622</td><td class="hits">26</td><td class="source">  return compiledTemplate;</td></tr><tr><td class="line">623</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">624</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">625</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">626</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">627</td><td class="hits"></td><td class="source"> * Merge options together</td></tr><tr><td class="line">628</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">629</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">630</td><td class="hits">1</td><td class="source">function createOptions(req, res, options) {</td></tr><tr><td class="line">631</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">632</td><td class="hits"></td><td class="source">  // Merge options with helpers</td></tr><tr class="hit"><td class="line">633</td><td class="hits">22</td><td class="source">  options = merge(options, req.helpers);</td></tr><tr><td class="line">634</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">635</td><td class="hits"></td><td class="source">  // Merge options with application data</td></tr><tr class="hit"><td class="line">636</td><td class="hits">22</td><td class="source">  if (calipso.data) {</td></tr><tr class="hit"><td class="line">637</td><td class="hits">22</td><td class="source">    options = merge(options, calipso.data);</td></tr><tr><td class="line">638</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">639</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">640</td><td class="hits">22</td><td class="source">  return options;</td></tr><tr><td class="line">641</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">642</td><td class="hits"></td><td class="source">}</td></tr></tbody></table></div><div class="file"><h2 id="core/Utils.js">core/Utils.js</h2><div id="stats" class="low"><div class="percentage">41%</div><div class="sloc">24</div><div class="hits">10</div><div class="misses">14</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * General utility methods</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">4</td><td class="hits">1</td><td class="source">var _ = require('underscore');</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">6</td><td class="hits">1</td><td class="source">module.exports = {</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source">  /**</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source">   * Basically like getProperty, different return</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source">   * @method hasProperty</td></tr><tr><td class="line">10</td><td class="hits"></td><td class="source">   * @param ns {string} A period delimited string of the namespace to find, sans root object</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">   * @param obj {object} The root object to search</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">   * @return {boolean} true if property exists, false otherwise</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">   */</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source">  hasProperty: function(ns, obj) {</td></tr><tr class="hit"><td class="line">15</td><td class="hits">2</td><td class="source">    if (!ns) {</td></tr><tr class="miss"><td class="line">16</td><td class="hits">0</td><td class="source">      return obj;</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source">    }</td></tr><tr class="hit"><td class="line">18</td><td class="hits">2</td><td class="source">    var nsArray = ns.split('.'),</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source">      nsLen = nsArray.length,</td></tr><tr><td class="line">20</td><td class="hits"></td><td class="source">      newNs;</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">    // if nsLen === 0, then obj is just returned</td></tr><tr class="hit"><td class="line">23</td><td class="hits">2</td><td class="source">    while (nsLen &gt; 0) {</td></tr><tr class="hit"><td class="line">24</td><td class="hits">6</td><td class="source">      newNs = nsArray.shift();</td></tr><tr class="hit"><td class="line">25</td><td class="hits">6</td><td class="source">      if (obj[newNs]) {</td></tr><tr class="hit"><td class="line">26</td><td class="hits">4</td><td class="source">        obj = obj[newNs];</td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">      } else {</td></tr><tr class="hit"><td class="line">28</td><td class="hits">2</td><td class="source">        return false;</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">      }</td></tr><tr class="hit"><td class="line">30</td><td class="hits">4</td><td class="source">      nsLen = nsArray.length;</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">32</td><td class="hits">0</td><td class="source">    return true;</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">  /**</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">   * Find a namespaced property</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">   * @method getProperty</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">   * @param ns {string} A period delimited string of the namespace to find, sans root object</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">   * @param obj {object} The root object to search</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">   * @return {object} the object, either the namespaced obejct or the root object</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source">   */</td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">  getProperty: function(ns, obj) {</td></tr><tr class="miss"><td class="line">42</td><td class="hits">0</td><td class="source">    if (!ns) {</td></tr><tr class="miss"><td class="line">43</td><td class="hits">0</td><td class="source">      return obj;</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">45</td><td class="hits">0</td><td class="source">    var nsArray = ns.split('.'),</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source">      nsLen = nsArray.length,</td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">      newNs;</td></tr><tr><td class="line">48</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">49</td><td class="hits"></td><td class="source">    // if nsLen === 0, then obj is just returned</td></tr><tr class="miss"><td class="line">50</td><td class="hits">0</td><td class="source">    while (nsLen &gt; 0) {</td></tr><tr class="miss"><td class="line">51</td><td class="hits">0</td><td class="source">      newNs = nsArray.shift();</td></tr><tr class="miss"><td class="line">52</td><td class="hits">0</td><td class="source">      if (obj[newNs]) {</td></tr><tr class="miss"><td class="line">53</td><td class="hits">0</td><td class="source">        obj = obj[newNs];</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">      }</td></tr><tr class="miss"><td class="line">55</td><td class="hits">0</td><td class="source">      nsLen = nsArray.length;</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">    }</td></tr><tr class="miss"><td class="line">57</td><td class="hits">0</td><td class="source">    return obj;</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">  },</td></tr><tr><td class="line">59</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source">  /**</td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">   * Simple mongo object copier, used to do a shallow copy of objects</td></tr><tr><td class="line">62</td><td class="hits"></td><td class="source">   */</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source">  copyMongoObject: function(object, copy, schema) {</td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source"> </td></tr><tr class="miss"><td class="line">65</td><td class="hits">0</td><td class="source">    var fields = _.keys(schema.paths);</td></tr><tr class="miss"><td class="line">66</td><td class="hits">0</td><td class="source">    _.each(fields, function(key) {</td></tr><tr class="miss"><td class="line">67</td><td class="hits">0</td><td class="source">      if (key !== '_id') copy.set(key, object.get(key));</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">69</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">};</td></tr></tbody></table></div><div class="file"><h2 id="client/Client.js">client/Client.js</h2><div id="stats" class="high"><div class="percentage">100%</div><div class="sloc">44</div><div class="hits">44</div><div class="misses">0</div></div><table id="source"><thead><tr><th>Line</th><th>Hits</th><th>Source</th></tr></thead><tbody><tr><td class="line">1</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">2</td><td class="hits"></td><td class="source"> * This library provides a wrapper to enable modules to load javascript and styles into an</td></tr><tr><td class="line">3</td><td class="hits"></td><td class="source"> * array, that can then be rendered into a theme in the appropriate location.</td></tr><tr><td class="line">4</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">5</td><td class="hits"></td><td class="source"> * Styles and JS are all indexed by key, so you could write functions that over-wrote them in the theme as the</td></tr><tr><td class="line">6</td><td class="hits"></td><td class="source"> * last update will always stick.</td></tr><tr><td class="line">7</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">8</td><td class="hits"></td><td class="source"> */</td></tr><tr><td class="line">9</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">10</td><td class="hits">1</td><td class="source">var rootpath = process.cwd() + '/',</td></tr><tr><td class="line">11</td><td class="hits"></td><td class="source">  path = require('path'),</td></tr><tr><td class="line">12</td><td class="hits"></td><td class="source">  calipso = require(path.join('..', 'calipso')),</td></tr><tr><td class="line">13</td><td class="hits"></td><td class="source">  fs = require('fs');</td></tr><tr><td class="line">14</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">15</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">16</td><td class="hits"></td><td class="source"> * Client Object - handle CSS and JS loading for modules out to themes</td></tr><tr><td class="line">17</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">18</td><td class="hits">1</td><td class="source">var Client = module.exports = function Client(options) {</td></tr><tr><td class="line">19</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">20</td><td class="hits">14</td><td class="source">    this.options = options || {</td></tr><tr><td class="line">21</td><td class="hits"></td><td class="source">      'minified-script': 'media/calipso-main'</td></tr><tr><td class="line">22</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">23</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">24</td><td class="hits">14</td><td class="source">    this.scripts = [];</td></tr><tr class="hit"><td class="line">25</td><td class="hits">14</td><td class="source">    this.styles = [];</td></tr><tr><td class="line">26</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">27</td><td class="hits"></td><td class="source">    // Shortcuts to core, must be included somewhere (module or theme) to be rendered</td></tr><tr class="hit"><td class="line">28</td><td class="hits">14</td><td class="source">    this.coreScripts = {</td></tr><tr><td class="line">29</td><td class="hits"></td><td class="source">      'jquery': {</td></tr><tr><td class="line">30</td><td class="hits"></td><td class="source">        key: 'jquery',</td></tr><tr><td class="line">31</td><td class="hits"></td><td class="source">        url: 'jquery-1.6.4.min.js',</td></tr><tr><td class="line">32</td><td class="hits"></td><td class="source">        weight: -100</td></tr><tr><td class="line">33</td><td class="hits"></td><td class="source">      },</td></tr><tr><td class="line">34</td><td class="hits"></td><td class="source">      'calipso': {</td></tr><tr><td class="line">35</td><td class="hits"></td><td class="source">        key: 'calipso',</td></tr><tr><td class="line">36</td><td class="hits"></td><td class="source">        url: 'calipso.js',</td></tr><tr><td class="line">37</td><td class="hits"></td><td class="source">        weight: -50</td></tr><tr><td class="line">38</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">39</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">40</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">41</td><td class="hits"></td><td class="source">  };</td></tr><tr><td class="line">42</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">43</td><td class="hits">1</td><td class="source">Client.prototype.addScript = function(options) {</td></tr><tr><td class="line">44</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">45</td><td class="hits">8</td><td class="source">  var self = this;</td></tr><tr><td class="line">46</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">47</td><td class="hits"></td><td class="source">  // Convert our options over with flexible defaults</td></tr><tr class="hit"><td class="line">48</td><td class="hits">8</td><td class="source">  if (typeof options === &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">49</td><td class="hits">2</td><td class="source">    if (this.coreScripts[options]) {</td></tr><tr class="hit"><td class="line">50</td><td class="hits">1</td><td class="source">      options = this.coreScripts[options];</td></tr><tr><td class="line">51</td><td class="hits"></td><td class="source">    } else {</td></tr><tr class="hit"><td class="line">52</td><td class="hits">1</td><td class="source">      options = {</td></tr><tr><td class="line">53</td><td class="hits"></td><td class="source">        name: options,</td></tr><tr><td class="line">54</td><td class="hits"></td><td class="source">        url: options,</td></tr><tr><td class="line">55</td><td class="hits"></td><td class="source">        weight: 0</td></tr><tr><td class="line">56</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">57</td><td class="hits"></td><td class="source">    }</td></tr><tr><td class="line">58</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">59</td><td class="hits">12</td><td class="source">  if (!options.name) options.name = options.url;</td></tr><tr><td class="line">60</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">61</td><td class="hits"></td><td class="source">  // Add the script</td></tr><tr class="hit"><td class="line">62</td><td class="hits">8</td><td class="source">  self._add('scripts', options.name, options);</td></tr><tr><td class="line">63</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">64</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">65</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">66</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">67</td><td class="hits"></td><td class="source"> * Create simple list of all client JS</td></tr><tr><td class="line">68</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">69</td><td class="hits">1</td><td class="source">Client.prototype.listScripts = function(next) {</td></tr><tr><td class="line">70</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">71</td><td class="hits"></td><td class="source">  // TODO - this should be updated to use LABjs by default (?)</td></tr><tr class="hit"><td class="line">72</td><td class="hits">1</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">73</td><td class="hits">1</td><td class="source">  var output = &quot;&lt;!-- Calipso Module Scripts --&gt;&quot;;</td></tr><tr class="hit"><td class="line">74</td><td class="hits">1</td><td class="source">  self.scripts.forEach(function(value) {</td></tr><tr class="hit"><td class="line">75</td><td class="hits">2</td><td class="source">    output += '\r\n&lt;script title=&quot;' + value.name + '&quot; src=&quot;' + value.url + '&quot;&gt;&lt;/script&gt;';</td></tr><tr><td class="line">76</td><td class="hits"></td><td class="source">  });</td></tr><tr class="hit"><td class="line">77</td><td class="hits">1</td><td class="source">  output += &quot;&lt;!-- End of Calipso Module Scripts --&gt;&quot;;</td></tr><tr class="hit"><td class="line">78</td><td class="hits">1</td><td class="source">  next(null, output);</td></tr><tr><td class="line">79</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">80</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">81</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">82</td><td class="hits">1</td><td class="source">Client.prototype.addStyle = function(options) {</td></tr><tr><td class="line">83</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">84</td><td class="hits">5</td><td class="source">  var self = this;</td></tr><tr><td class="line">85</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">86</td><td class="hits"></td><td class="source">  // Convert our options over with flexible defaults</td></tr><tr class="hit"><td class="line">87</td><td class="hits">5</td><td class="source">  if (typeof options === &quot;string&quot;) {</td></tr><tr class="hit"><td class="line">88</td><td class="hits">1</td><td class="source">    options = {</td></tr><tr><td class="line">89</td><td class="hits"></td><td class="source">      name: options,</td></tr><tr><td class="line">90</td><td class="hits"></td><td class="source">      url: options,</td></tr><tr><td class="line">91</td><td class="hits"></td><td class="source">      weight: 0</td></tr><tr><td class="line">92</td><td class="hits"></td><td class="source">    };</td></tr><tr><td class="line">93</td><td class="hits"></td><td class="source">  }</td></tr><tr class="hit"><td class="line">94</td><td class="hits">8</td><td class="source">  if (!options.name) options.name = options.url;</td></tr><tr><td class="line">95</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">96</td><td class="hits"></td><td class="source">  // Add the script</td></tr><tr class="hit"><td class="line">97</td><td class="hits">5</td><td class="source">  self._add('styles', options.name, options);</td></tr><tr><td class="line">98</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">99</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">100</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">101</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">102</td><td class="hits"></td><td class="source"> * Compile together all of the client side scripts</td></tr><tr><td class="line">103</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">104</td><td class="hits">1</td><td class="source">Client.prototype.listStyles = function(next) {</td></tr><tr><td class="line">105</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">106</td><td class="hits"></td><td class="source">  // TODO - this should be updated to use LABjs by default (?)</td></tr><tr class="hit"><td class="line">107</td><td class="hits">1</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">108</td><td class="hits">1</td><td class="source">  var output = &quot;&lt;!-- Calipso Module Styles --&gt;&quot;;</td></tr><tr><td class="line">109</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">110</td><td class="hits">1</td><td class="source">  self.styles.forEach(function(value) {</td></tr><tr class="hit"><td class="line">111</td><td class="hits">2</td><td class="source">    output += '\r\n&lt;link rel=&quot;stylesheet&quot; title=&quot;' + value.name + '&quot; href=&quot;' + value.url + '&quot;/&gt;';</td></tr><tr><td class="line">112</td><td class="hits"></td><td class="source">  });</td></tr><tr class="hit"><td class="line">113</td><td class="hits">1</td><td class="source">  output += &quot;&lt;!-- End of Calipso Module Styles --&gt;&quot;;</td></tr><tr class="hit"><td class="line">114</td><td class="hits">1</td><td class="source">  next(null, output);</td></tr><tr><td class="line">115</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">116</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">117</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">118</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">119</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">120</td><td class="hits"></td><td class="source"> * Helper to add unique elements to an array</td></tr><tr><td class="line">121</td><td class="hits"></td><td class="source"> */</td></tr><tr class="hit"><td class="line">122</td><td class="hits">1</td><td class="source">Client.prototype._add = function(arrName, name, options) {</td></tr><tr><td class="line">123</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">124</td><td class="hits">13</td><td class="source">  var self = this;</td></tr><tr class="hit"><td class="line">125</td><td class="hits">13</td><td class="source">  self[arrName] = self[arrName] || [];</td></tr><tr><td class="line">126</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">127</td><td class="hits"></td><td class="source">  // Find first match</td></tr><tr class="hit"><td class="line">128</td><td class="hits">13</td><td class="source">  var found = calipso.lib._.find(self[arrName], function(value) {</td></tr><tr class="hit"><td class="line">129</td><td class="hits">3</td><td class="source">    return (value.name &amp;&amp; value.name === name) ? true : false;</td></tr><tr><td class="line">130</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">131</td><td class="hits"></td><td class="source"> </td></tr><tr class="hit"><td class="line">132</td><td class="hits">13</td><td class="source">  if (found) {</td></tr><tr><td class="line">133</td><td class="hits"></td><td class="source">    // Replace - this means we never get duplicates (e.g. of JQuery, JQueryUI)</td></tr><tr class="hit"><td class="line">134</td><td class="hits">1</td><td class="source">    self[arrName].splice(found, 1, options);</td></tr><tr><td class="line">135</td><td class="hits"></td><td class="source">  } else {</td></tr><tr><td class="line">136</td><td class="hits"></td><td class="source">    // Push</td></tr><tr class="hit"><td class="line">137</td><td class="hits">12</td><td class="source">    self[arrName].push(options);</td></tr><tr><td class="line">138</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">139</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">140</td><td class="hits"></td><td class="source">  // Sort - TODO, this can probably be more efficient by placing the new item smarter</td></tr><tr class="hit"><td class="line">141</td><td class="hits">13</td><td class="source">  self[arrName].sort(function(a, b) {</td></tr><tr class="hit"><td class="line">142</td><td class="hits">2</td><td class="source">    return a.weight &gt; b.weight;</td></tr><tr><td class="line">143</td><td class="hits"></td><td class="source">  });</td></tr><tr><td class="line">144</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">145</td><td class="hits"></td><td class="source">};</td></tr><tr><td class="line">146</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">147</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">148</td><td class="hits"></td><td class="source">/**</td></tr><tr><td class="line">149</td><td class="hits"></td><td class="source"> * Compile together all of the client side scripts</td></tr><tr><td class="line">150</td><td class="hits"></td><td class="source"> * TODO - this is currently not used, needs to be worked on and thought through.</td></tr><tr><td class="line">151</td><td class="hits"></td><td class="source"> *</td></tr><tr><td class="line">152</td><td class="hits"></td><td class="source">Client.prototype.compile = function(next) {</td></tr><tr><td class="line">153</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">154</td><td class="hits"></td><td class="source">  var self = this;</td></tr><tr><td class="line">155</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">156</td><td class="hits"></td><td class="source">  try {</td></tr><tr><td class="line">157</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">158</td><td class="hits"></td><td class="source">    var scriptFile = path.join(rootpath,self.options.script),</td></tr><tr><td class="line">159</td><td class="hits"></td><td class="source">        scriptStream = fs.createWriteStream(scriptFile, {'flags': 'a'});</td></tr><tr><td class="line">160</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">161</td><td class="hits"></td><td class="source">  } catch(ex) {</td></tr><tr><td class="line">162</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">163</td><td class="hits"></td><td class="source">    console.dir(ex);</td></tr><tr><td class="line">164</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">165</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">166</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">167</td><td class="hits"></td><td class="source">  var grabFile = function(item, callback) {</td></tr><tr><td class="line">168</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">169</td><td class="hits"></td><td class="source">    // TODO - allow referential</td></tr><tr><td class="line">170</td><td class="hits"></td><td class="source">    var filePath = path.join(rootpath, item.url);</td></tr><tr><td class="line">171</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">172</td><td class="hits"></td><td class="source">    // Check to see if the file has changed</td></tr><tr><td class="line">173</td><td class="hits"></td><td class="source">    var stat = fs.lstatSync(filePath);</td></tr><tr><td class="line">174</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">175</td><td class="hits"></td><td class="source">    fs.readFile(filePath, 'utf8', function(err, contents) {</td></tr><tr><td class="line">176</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">177</td><td class="hits"></td><td class="source">      if(err) {</td></tr><tr><td class="line">178</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">179</td><td class="hits"></td><td class="source">        return callback(new Error(&quot;Unable to locate file for ClientJS creation: &quot; + filePath));</td></tr><tr><td class="line">180</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">181</td><td class="hits"></td><td class="source">      } else {</td></tr><tr><td class="line">182</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">183</td><td class="hits"></td><td class="source">        var drain;</td></tr><tr><td class="line">184</td><td class="hits"></td><td class="source">        drain = scriptStream.write(contents);</td></tr><tr><td class="line">185</td><td class="hits"></td><td class="source">        callback(null, stat.mtime);</td></tr><tr><td class="line">186</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">187</td><td class="hits"></td><td class="source">      }</td></tr><tr><td class="line">188</td><td class="hits"></td><td class="source">    });</td></tr><tr><td class="line">189</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">190</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">191</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">192</td><td class="hits"></td><td class="source">  // Callback wrapper to close the streams</td></tr><tr><td class="line">193</td><td class="hits"></td><td class="source">  var done = function(err, data) {</td></tr><tr><td class="line">194</td><td class="hits"></td><td class="source">    scriptStream.end();</td></tr><tr><td class="line">195</td><td class="hits"></td><td class="source">    next(err, data);</td></tr><tr><td class="line">196</td><td class="hits"></td><td class="source">  }</td></tr><tr><td class="line">197</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">198</td><td class="hits"></td><td class="source">  // var contents = fs.readFileSync(config.out, 'utf8');</td></tr><tr><td class="line">199</td><td class="hits"></td><td class="source">  calipso.lib.async.mapSeries(self.scripts, grabFile, function(err, scripts) {</td></tr><tr><td class="line">200</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">201</td><td class="hits"></td><td class="source">      if(err) return done(err);</td></tr><tr><td class="line">202</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">203</td><td class="hits"></td><td class="source">      var reduce = function(context, memo, value, index, list) {</td></tr><tr><td class="line">204</td><td class="hits"></td><td class="source">        return (value &gt; memo) ? value : memo;</td></tr><tr><td class="line">205</td><td class="hits"></td><td class="source">      };</td></tr><tr><td class="line">206</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">207</td><td class="hits"></td><td class="source">      var maxmtime = calipso.lib._.reduce(scripts, reduce);</td></tr><tr><td class="line">208</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">209</td><td class="hits"></td><td class="source">      console.dir(maxmtime);</td></tr><tr><td class="line">210</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">211</td><td class="hits"></td><td class="source">      var script = '&lt;!-- ' + maxmtime + ' --&gt;'</td></tr><tr><td class="line">212</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">213</td><td class="hits"></td><td class="source">      done(null, script);</td></tr><tr><td class="line">214</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">215</td><td class="hits"></td><td class="source">  })</td></tr><tr><td class="line">216</td><td class="hits"></td><td class="source"> </td></tr><tr><td class="line">217</td><td class="hits"></td><td class="source">}</td></tr><tr><td class="line">218</td><td class="hits"></td><td class="source">**/</td></tr></tbody></table></div></div></div></body></html>